how many decimal digits does float supports? - c

int main(){
int s=200;
printf("%.12f",s/3.0);
}
How this program is giving output 66.666666666667 even though float can support up to only 6-7 decimal places?
Meanwhile,
int main(){
float s=200;
printf("%.12f",s/3);
}
gives 66.666664123535.
please help?

There isn't any float in the first program. %f is double and 3.0 is also double. The double type has about 16 decimal digits precision. In the second program the float is promoted to double for the variadic function but does not magically gain more precision.
From C11 § 6.4.4.2
4 An unsuffixed floating constant has type double. If suffixed by the letter f or F, it has type float. If suffixed by the letter l or L, it has type long double.
and C11 § 6.5.2.2
6 If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double.
7 If the expression that denotes the called function has a type that does include a prototype, the arguments are implicitly converted, as if by assignment, to the types of the corresponding parameters, taking the type of each parameter to be the unqualified version of its declared type. The ellipsis notation in a function prototype declarator causes argument type conversion to stop after the last declared parameter. The default argument promotions are performed on trailing arguments.

Only if the precision was missing, it would have been taken as 6. Otherwise, if you specify the precision, it's going to honor that.
Quoting C11, chapter 7.21.6.1/P8, (emphasis mine)
f,F
A double argument representing a floating-point number is converted to decimal notation in the style [-]ddd.ddd, where the number of digits after the decimal-point character is equal to the precision specification. If the precision is missing, it is taken as 6; [...]

In most C implementations, float and double do not use decimal digits. They use binary.
In the first program, 3.0 is a double, so s/3.0 is computed with double arithmetic. In spite of f being the initial letter of float, %.12f takes a double argument, for reasons involving the history of C development. So the double value s/3.0 is converted to decimal with 12 digits after the decimal point and printed.
In the second program, s is a float, so s/3 is computed with float arithmetic. In the format you use, the result is a binary-based number, 8738133 • 2−17. The reason there are many decimal digits involved is that, while expressing 2−17 is simple using that base of 2, in decimal it is 0.00000762939453125. then 8738133 times that is 66.66666412353515625. Since you asked for only 12 digits, you see 66.6666641235. (Note: The float value is converted to double to be passed to printf, but this does not change the value.)

Related

K&R C Chapter exercise int to float?

Section 1.3 of Kernighan and Ritchie uses the following temperature conversion program to introduce For statements:
#include <stdio.h>
/* print Fahrenheit-Celsius table */
int main(){
int fahr;
for (fahr = 0; fahr <= 300; fahr = fahr + 20)
printf("%3d %6.1f\n", fahr, (5.0/9.0)*(fahr-32));
}
What it doesn't explain is how this program can make use of an int variable to produce float values without an error. What makes this valid? Don't all the variables in an equation have to be of the same type? I'm hesitant to move forward without understanding this.
The conversion are implicit, but enabling warnings should give you a message explaining that int is being converted to double.
Here (5.0/9.0)*(fahr-32)), a double is being multiplied by an int, and the int is converted to double using usual arithmetic conversions.
The types in arithmetic don't necessarily have to match. C has a whole chapter dedicated to conversions: 6.3 Conversions, 6.3.1 Arithmetic operands.
Actually it doesn't: (5.0/9.0)*(fahr-32) is an expression of type double, not a float.
The reason being that 5.0 and 9.0 are double literals and the (fahr - 32) is promoted to that type before the multiplication takes place.
If you really want a float then use (5.0f/9.0f)*(fahr-32). Note the suffixed f on the numbers (and you will need to suffix both).
%f is an appropriate format specifier in printf for a double and a float, so there are no problems there.
In an arithmetic expression, if two operands are of different types (such as int and double), the operand with the lower precision will be converted to the same type as the operand with the higher precision. The exact rules can be found in section 6.3.1.8 of the online C 2011 standard.
Note that this only applies for arithmetic (integer and floating-point) types, not for pointer or aggregate types.
The reason an int can be promoted to a double without a problem -- assuming int represents a 32-bit integer and double represents a 64-bit IEEE floating point number, which is common -- is that a double has 53 bits of precision, so it has no trouble representing a 32-bit integer without loss. Any warning would just be informational and not a cause for concern, unlike when a 32-bit integer is coerced to a float, which only has 24 bits of precision and thus could lose up to eight bits (seven for a signed int) of precision in the cast.

Float and int comparision

In below program, i didnt understand how float and int value are same.
int main()
{
int a=3;
float b=3.0;
if(a==b)
{
printf("A is equal to b");
}
else{
printf("A is not euql to b");
}
}
The output of the program is "A is equal to b"
if(a==b) does not compare types, it compares values.
As #Kerrek SB commented, the value(s) are converted to a common type.
Each a and b go though "usual arithmetic conversions" before the comparison.
... the values yielded by operators with floating operands and values subject to the usual arithmetic conversions and of floating constants are evaluated to a format whose range and precision may be greater than required by the type. The use of evaluation formats is characterized by the implementation-defined value of FLT_EVAL_METHOD: C11dr §5.2.4.2.2 9
Conversion to floating point is to float, double or long double depending on FLT_EVAL_METHOD.
Assuming conversion to float...:
Otherwise, if the corresponding real type of either operand is float, the other operand is converted, without change of type domain, to a type whose
corresponding real type is float. §6.3.1.8 1
So a converts to a float with the value of 3.0 before the comparison.
Since the values compare the same, they pass the if(a==b).
Note: Conversion can cause issues as not all int may covert exactly to a float.
Actually the int value will be typecasted to float and then the if condition is evaluated.

Why can we use %d for both scanf and printf?

scanf needs %lf for doubles and printf is okay with just %f
So, why is printf and scanf okay with %d?
This is what I think the reason is:
A floating point (%f) uses exactly 64 bits whereas a double floating-point number (%lf) uses at least 32. The compiler doesn't know how many bits to assign to a variable that is being scanned in by scanf, so we use %lf to tell the compiler that it needs to be at least 32 bits.
Okay... but then why do we use %d for both scanf and printf? Why not %ld and %d? %ld doesn't exist in C for starters. %d is a signed decimal number that needs at least 16 bits. You're already telling the compiler what the lower bound is in how many bits to allocate to it, so it is okay for scanf. This is also why we don't have a %ld.
Please do correct me if I am wrong or inform me what I can do to make this answer better. I'm pretty sure it is not a perfect answer.
You can think scanf as converting input stream into variables that defined in your code. Thus, scanf needs to know the exactly size for each variable. In general, the 32-bit and 64-bit IEEE 754 binary floating-point formats are used in C. So, %f means 32-bit and %lf means 64-bit.
Besides %ld exists and it means 32-bit integer. %lld also exists which means 64-bit integer. The above wiki site explains all C data types very well.
See §6.5.2.2/6-7 in the C99 standard.
§6.5.2.2/6 defines the default argument promotions: (emphasis added)
the integer promotions are performed on each argument, and arguments that have type float are promoted to double.
and specifies that these promotions are performed on arguments to a function declared with no prototype (that is, with an empty parameter list () instead of (void), where the latter is used to indicate no arguments).
Paragraph 7 additionally specifies that if the prototype of the function has a trailing ellipsis (...):
The ellipsis notation in a function prototype declarator causes argument type conversion to stop after the last declared parameter. The default argument promotions are performed on trailing arguments.
The integer promotions are defined in §6.3.1.1/2; they apply to
objects or expressions of an integer type whose "integer conversion rank is less than or equal to the rank of int and unsigned int": roughly speaking, any smaller integer type, such as boolean or character types;
bit-fields of type _Bool, int, signed int or unsigned int.
If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; otherwise, it is converted to an unsigned
int. These are called the integer promotions.
All other types are unchanged by the integer promotions.
In short, if you have varargs function, such as printf or scanf:
Integer arguments which are no larger than int are converted to (possibly unsigned) int. (This does not include long.)
Floating point arguments which are no larger than double are converted to double. (This includes float.)
Pointers are unaltered.
Other non-pointer types are unaltered.
So printf doesn't need to distinguish between float and double, because it will never be passed a float. It does need to distinguish between int and long.
But scanf does need to know whether an argument is a pointer to a float or a pointer to a double, because pointers are unchanged by the default argument promotions.

Implicit types for numbers in C

What are the implicit types for numbers in C? If, for example, I have a decimal number in a calculation, is the decimal always treated as a double? If I have a non-decimal number, is it always treated as an int? What if my non-decimal number is larger than an int value?
I'm curious because this affects type conversion and promotion. For instance, if I have the following calculation:
float a = 1.0 / 25;
Is 1.0 treated as a double and 25 treated as an int? Is 25 then promoted to a double, the calculation performed at double precision and then the result converted to a float?
What about:
double b = 1 + 2147483649; // note that the number is larger than an int value
If the number has neither a decimal point nor an exponent, it is an integer of some sort; by default, an int.
If the number has a decimal point or an exponent, it is a floating point number of some sort; by default, a double.
That's about it. You can append suffixes to numbers (such as ULL for unsigned long long) to specify the type more precisely. Otherwise (simplifying a little), integers are the smallest int type (of type int or longer) that will hold the value.
In your examples, the code is:
float a = 1.0 / 25;
double b = 1 + 2147483649;
The value of a is calculated by noting that 1.0 is a double and 25 is an integer. When processing the division, the int is converted to a double, the calculation is performed (producing a double), and the result is then coerced into a float for assignment to a. All of this can be done by the compiler, so the result will be pre-computed.
Similarly, on a system with 32-bit int, the value 214783649 is too big to be an int, so it will be treated as a signed type bigger than int (either long or long long); the 1 is added (yielding the same type), and then that value is converted to a double. Again, it is all done at compile time.
These computations are governed by the same rules as other computations in C.
The type rules for integer constants are detailed in §6.4.4.1 Integer constants of ISO/IEC 9899:1999. There's a table which details the types depending on the suffix (if any) and the type of constant (decimal vs octal or hexadecimal). For decimal constants, the value is always a signed integer; for octal or hexadecimal constants, the type can be signed or unsigned as required, and as soon as the value fits. Thanks to Daniel Fischer for pointing out my mistake.
http://en.wikipedia.org/wiki/Type_conversion
The standard has a general guideline for what you can expect but compilers have a superset of rules that encompass the standard as well as rules for optimizing. The above link discusses some of the the generalities you can expect. If you are concerned about the implicit coercion it is typically good practice to use explicit casting.
Keep in mind that the size of the primitive types is not guaranteed.
1.0 / 25
Evaluates to a double because one of the operands is a double. If you changed it to 1/25 the evaluation is performed as two integers and evaluates to 0.
double b = 1 + 2147483649;
The right side is evaluated as an integer and then coerced to a double during assignment.
actually. in your example you may get a compiler warning. You'd either write 1.0f to make it a float to start with, or explicitly cast your result before assigning it.

Integer to floating conversion in C

float f1 = 123.125;
int i1 = -150;
f1 = i1; // integer to floating conversion
printf("%i assigned to an float produces %f\n", i1, f1);
Output:
-150 assigned to an float produces -150.000000
My question is why the result has 6 zeros (000000) after the . and not 7 or 8 or some number?
That's just what printf does. See the man page where it says
f, F
The double argument shall be converted to decimal notation in the style "[-]ddd.ddd", where the number of digits after the radix character is equal to the precision specification. If the precision is missing, it shall be taken as 6; if the precision is explicitly zero and no '#' flag is present, no radix character shall appear. If a radix character appears, at least one digit appears before it. The low-order digit shall be rounded in an implementation-defined manner.
(emphasis mine)
It has nothing to do with how 150 is represented as a floating point number in memory (and in fact, it's promoted to a double because printf is varargs).
The number of zeros you see is a result of the default precision used by the %f printf conversion. It's basically unrelated to the integer to floating point conversion.
Because the C standard (§7.19.6.1) says that in the absence of information to the contrary, %f will print 6 decimal places.
f,F A double argument representing a floating-point number is converted to
decimal notation in the style [−]ddd.ddd, where the number of digits after
the decimal-point character is equal to the precision specification. If the
precision is missing, it is taken as 6; if the precision is zero and the # flag is
not specified, no decimal-point character appears.
Floating point arithmetic is not exact. printf is just showing that number of zeroes.
From the documentation:
The default number of digits after the
decimal point is six, but this can be
changed with a precision field. If a
decimal point appears, at least one
digit appears before it. The "double"
value is rounded to the correct number
of decimal places.

Resources