behaviour of float in C - c

#include<stdio.h>
int main()
{
float f = 0.1;
double d = 0.1;
printf("%lu %lu %lu %lu\n", sizeof(f), sizeof(0.1f), sizeof(0.1), sizeof(d));
return 0;
}
Output
$ ./a.out
4 4 8 8
As per above code, we can see sizeof(0.1) and sizeof(0.1f) are not same.
sizeof(0.1) is 8 bytes, while sizeof(0.1f) is 4 bytes.
but while assigning the value to float variable f, it automatically truncates its size to 4 bytes.
While in below code, while comparing it with float x it is not truncating and 4 bytes of float are compared with 8 bytes of 0.1, value of float x matches with 0.1f as both are of 4 bytes.
#include<stdio.h>
int main()
{
float x = 0.1;
if (x == 0.1)
printf("IF");
else if (x == 0.1f)
printf("ELSE IF");
else
printf("ELSE");
}
Output
$ ./a.out
ELSE IF
why and how it is truncating while assigning and not while comparing?

A floating point literal without a suffix is of type double. Suffixing it with an f makes a literal of type float.
When assigning to a variable, the right operand to = is converted to the type of the left operand, thus you observe truncation.
When comparing, the operands to == are converted to the larger of the two operands, so x == 0.1 is like (double)x == 0.1, which is false since (double)(float)0.1 is not equal to 0.1 due to rounding issues. In x == 0.1f, both operands have type float, which results in equality on your machine.
Floating point math is tricky, read the standard for more details.

a floating point constant like 0.1 is a double unless specified as a float like 0.1f. The line
float f = 0.1;
means create a double with value 0.1 and cast it to float and lose precision in the process. The lines
float x = 0.1;
if (x == 0.1)
will cause x to be implicitly converted to double but it will have a slightly different value than for e.g. double x = 0.1;

0.1f (the "f" after the number) is for the computer as float , that how your compailer know that he need to store it as float and not as double.
so float 0.1 not equal to 0.1 , its equal to 0.1f

when you write 0.1 , it is considered by default as double. suffix f explicitly make it float.
In second question float are stored as ieee standard so it it's going in else if because equivalent conversion of 0.1f to double is not same.
https://en.wikipedia.org/wiki/Floating_point

0.1 is a double value whereas 0.1f is a float value.
The reason we can write float x=0.1 as well as double x=0.1 is due to implicit conversions .
But by using suffix f you make it a float type .
In this -
if(x == 0.1)
is flase because 0.1 is not exactly 0.1 at some places after decimal .There is also conversion in this to higher type i.e double.
Converting to float and then to double , there is loss of information as also double as higher precession than float so it differs .

Related

Similar codes output different results

The output of the following code is 0.0000000:
#include <stdio.h>
int main() {
float x;
x = (float)3.3 == 3.3;
printf("%f", x);
return 0;
}
Whereas this code outputs 1.000000:
int main() {
float x;
x = (float)3.5 == 3.5;
printf("%f", x);
return 0;
}
The only difference between the 2 codes is the value in the comparison, however, the results are not the same, why is this?
This line:
x=(float)3.3==3.3;
Compares (float)3.3 and 3.3 for equality and assigns the result to x. The left side of the comparison has type float because of the cast, while the right side has type double which is the default type for floating point constants.
The value 3.3 cannot be represented exactly in binary floating point, so the actual value stored is an approximation. This approximated value will be different for types float and double due to their differing precisions, so the equality will evaluated to false, i.e. 0. This is the value that gets assigned to x.
Regarding your comment on why x is 1 when the number you're checking is 3.5, that is because 3.5 can be represented exactly in binary, and both types have the precision to store that value, so they compare equal.
The assigned value 3.3 is a type of double but you're trying to compare a double with a float (by typecasting and due to this, precision losses).
The value of 3.3 as double is 3.299999999999999822 whereas the same value in float is measured 3.299999952F which are clearly unequal. Hence, the result will be true (i.e. 1.0000000) if you typecast the other 3.3 as float.
Rather than:
x = (float) 3.3 == 3.3; // float != double precision (precision loss)
If you do this:
x = (float) 3.3 == (float) 3.3; // converting both to make precision equal
Or,
x = (double) 3.3 == (double) 3.3; // converting . . . (same)
In other words, the comparison will be equal if you convert any one of the expression as same as the other one.
Also, notice that 3.5 is equal to 3.50000000... in both float and double, hence all the trailing zeroes are truncated from the assigned variable and hence you get 1.0000000. But this stuff is just a bit contrary with 3.3.
float has less precision than double, the value of 3.3 constant defaults to double and is 3.299999999999999822, the same constant when converted to float is 3.29999995231628418.
3.299999999999999822 == 3.29999995231628418 the result of this comparison is false i.e. 0.
Given the precedence rules, the expresssion amounts to x = ((float)3.5 == 3.5);, the comparison is evaluated first and the result is assigned to x.
When there is no cast both constants default to double so naturally the result of the comparison between them is true i.e. 1.
Regarding the comparison between 3.5 double and float being true, it has to do with the binary conversion, 3.3 is subjected to an aproximation given the fact that the mantissa conversion would go on indefinitely as can be seen in the link above, the exact value simply cannot be represented in double nor in float, whereas 3.5 is perfectly representable both in double and float alike.
To see loss of precision with float:
#include <stdio.h>
int main(){
float x = 3.3;
double d = 3.3;
printf("%12.9f %12.9lf\n",x, d);
Output:
3.299999952 3.300000000
3.3 in binary is
11.0100110011001100110011001100110011001100110011
When converted to float some bits of precision are truncated
11.0100110011001100110011001100110
When converted back to double, computer just uses 0's
11.0100110011001100110011001100110000000000000000
So
3.3 11.0100110011001100110011001100110011001100110011
(float)3.3 11.0100110011001100110011001100110
(double)((float)3.3) 11.0100110011001100110011001100110000000000000000
3.5 for comparison
3.5 11.1000000000000000000000000000000000000000000000
(float)3.5 11.1000000000000000000000000000000
(double)((float)3.5) 11.1000000000000000000000000000000000000000000000
Values like 3.3 cannot be represented exactly in a finite number of bits, just like the result of 1/3 cannot be represented exactly in a finite number of decimal digits, so you wind up storing an approximation of the value.
The float approximation is different from the double approximation, so the comparison (float) 3.3 == 3.3 fails.
By contrast, 3.5 can be represented exactly in both float and double types, so the comparison (float) 3.5 == 3.5 succeeds.
Just like with integer types, the significand of a floating-point type is a sum of powers of 2 - the value 3.5 is represented as 1.75 * 21, and the binary representation of the significand 1.75 is 1.112 - 1 * 20 + 1 * 2-1 + 1 * 2-2, or 1 + 0.5 + 0.25.
The issue is that you loose precision when converting the value 3.3, which is a literal of type double, to a float value with the cast (float)3.3. This loss of precision is irreversible, even if the comparison operator == will promote the left operand back to type double.
So the issue is that
(double)((float)3.3) == (double)3.3
will be false since the cast of 3.3 to float looses precision. For 3.5, in contrast, the result will be true, because 3.5 can be exactly represented as float in the same precision as double can.
Actually, the situation can be compared to casting a value from a higher rank to a lower and then back like in the following snippet:
unsigned int x = 257;
unsigned char y = x;
unsigned int x2 = y;
printf("%d\n", x==x2); // 0
x = 255;
y = x;
x2 = y;
printf("%d\n", x==x2); // 1

Comparison of a float with a value in C [duplicate]

This question already has answers here:
strange output in comparison of float with float literal
(8 answers)
Closed 5 years ago.
I have come across two programs in C, both comparing floating point number but with different outputs.
1)
#include<stdio.h>
int main()
{
float x = 0.1;
if (x == 0.1)
printf("IF");
else if (x == 0.1f)
printf("ELSE IF");
else
printf("ELSE");
}
Output : ELSE IF
2)
int main()
{
float x = 0.5;
if (x == 0.5)
printf("IF");
else if (x == 0.5f)
printf("ELSE IF");
else
printf("ELSE");
}
Output : IF
why 0.5 is not promoted to double whereas 0.1 is?
Since double is wider than float, x == 0.1 is interpreted as (double) x == 0.1.
This works for 0.5 because 0.5 is exactly representable in binary, so (double) 0.5f produces precisely 0.5. On the other hand, 0.1 has an infinite-digit representation in binary, and 0.1f and 0.1 end up being rounded to numbers that differ in how many initial digits of the sequence they hold.
In an analogy with decimal numbers, you can think of the above situation as trying to write down the fraction 1/3 by rounding it to a fixed number of decimal digits. Using a 5-significant-digit representation, you get 0.33333; choosing a 10-digit one results in 0.3333333333. Now, "casting" the five-digit number to ten digits results in 0.3333300000, which is a different number than 0.3333333333. In the same analogy, 0.5 in is like 1/10 in decimal, which would be represented as 0.10000 and 0.1000000000 respectively, so one could convert it to the other representation and back without changing its meaning.
If the contents of x is a marker value set from code, then simply compare it to 0.1f instead of to 0.1. If it is the result of a calculation, see Paul's answer for the correct way to compare floating-point quantities.
The proper way of comparing one floating point number with another is by using a precission value, for example
#define EPS 0.00001
#define ABS(a) ((a)<0?-(a):(a))
if (ABS(a-b)<EPS)
...
This is derived from:
if (a == b) // "equal" of fp numbers is not well defined
if (a-b == 0) // so comparing with zero is also ill defined
if (ABS(a-b) < EPS) // and so we compare with this small precission

Dividing integers in C rounds the value down / gives zero as a result

I'm trying to do some arithmetic on integers. The problem is when I'm trying to do division to get a double as a result, the result is always 0.00000000000000000000, even though this is obviously not true for something like ((7 * 207) / 6790). I have tried type-casting the formulas, but I still get the same result.
What am I doing wrong and how can I fix it?
int o12 = 7, o21 = 207, numTokens = 6790;
double e11 = ((o12 * o21) / numTokens);
printf(".%20lf", e11); // prints 0.00000000000000000000
Regardless of the actual values, the following holds:
int / int = int
The output will not be cast to a non-int type automatically.
So the output will be floored to an int when doing division.
What you want to do is force any of these to happen:
double / int = double
float / int = float
int / double = double
int / float = float
The above involves an automatic widening conversion - note that only one needs to be a floating point value.
You can do this by either:
Putting a (double) or (float) before one of your values to cast it to the corresponding type or
Changing one or more of the variables to double or float
Note that a cast like (double)(int / int) will not work, as this first does the integer division (which returns an int, and thus floors the value) and only then casts the result to double (this will be the same as simply trying to assign it to a double without any casting, as you've done).
It is certainly true for an expression such as ((7 * 207) / 6790) that the result is 0, or 0.0 if you think in double.
The expression only has integers, so it will be computed as an integer multiplication followed by an integer division.
You need to cast to a floating-point type to change that, e.g. ((7 * 207) / 6790.0).
Many poeple seem to expect the right-hand side of an assignment to be automatically "adjusted" by the type of the target variable: this is not how it works. The result is converted, but that doesn't affect any "inner" operations in the right-hand expression. In your code:
e11 = ((o12 * o21) / numTokens);
All of o12, o21 and numTokens are integer, so that expression is evaluated as integer, then converted to floating-point since e11 is double.
This like doing
const double a_quarter = 1 / 4;
this is just a simpler case of the same problem: the expression is evaluated first, then the result (the integer 0) is converted to double and stored. That's how the language works.
The fix is to cast:
e11 = ((o12 * o21) / (double) numTokens);
You must cast these numbers to double before division. When you perform division on int the result is also an integer rounded towards zero, e.g. 1 / 2 == 0, but 1.0 / 2.0 == 0.5.
If the operands are integer, C will perform integer arithmetic. That is, 1/4 == 0. However, if you force an operand to be double, then the arithmetic will take fractional parts into account. So:
int a = 1;
int b = 4;
double c = 1.0
double d = a/b; // d == 0.0
double e = c/b; // e == 0.25
double f = (double)a/b; // f == 0.25

Comparing float and double

#include <stdio.h>
int main(void){
float a = 1.1;
double b = 1.1;
if(a == b){
printf("if block");
}
else{
printf("else block");
}
return 0;
}
Prints: else block
#include <stdio.h>
int main(void){
float a = 1.5;
double b = 1.5;
if(a == b){
printf("if block");
}
else{
printf("else block");
}
return 0;
}
Prints: if block
What is the logic behind this?
Compiler used: gcc-4.3.4
This is because 1.1 is not exactly representable in binary floating-point. But 1.5 is.
As a result, the float and double representations will hold slightly different values of 1.1.
Here is exactly the difference when written out as binary floating-point:
(float) 1.1 = (0.00011001100110011001101)₂
(double)1.1 = (0.0001100110011001100110011001100110011001100110011010)₂
Thus, when you compare them (and the float version gets promoted), they will not be equal.
Must read: What Every Computer Scientist Should Know About Floating-Point Arithmetic
The exact value of 1.1 decimal in binary is non-ending fraction 1.00011001100110011001100(1100).... The double constant 1.1 is 53-bit truncation / approximate value of that mantissa. Now this when converted to float, the mantissa will be represented just in 24 bits.
When the float is converted back to double, the mantissa is now back to 53 bits, but all memory of the digits beyond 24 are lost - the value is zero-extended, and now you're comparing (for example, depending on the rounding behaviour)
1.0001100110011001100110011001100110011001100110011001
and
1.0001100110011001100110000000000000000000000000000000
Now, if you used 1.5 instead of 1.1;
1.5 decimal is exactly 1.1 in binary. It can be presented exactly in just 2 bit mantissa, therefore even the 24 bits of float are an exaggeration... what you have is
1.1000000000000000000000000000000000000000000000000000
and
1.10000000000000000000000
The latter, zero extended to a double would be
1.1000000000000000000000000000000000000000000000000000
which clearly is the same number.

What's the use of suffix `f` on float value

I am wondering what the difference is between these two variables in C:
float price = 3.00;
and
float price = 3.00f;
What is the use of suffix f in this case?
3.00 is interpreted as a double, as opposed to 3.00f which is seen by the compiler as a float.
The f suffix simply tells the compiler which is a float and which is a double.
See MSDN (C++)
In addition to what has already been said, keeping track of 1.0 versus 1.0f is more important than many people realize. If you write code like this:
float x;
...
float y = x * 2.0;
Then x will be promoted to a double, because 2.0 is a double. The compiler is not allowed to optimize that promotion away or it would violate the C standard. The calculation takes place with double precision, and then the result is then implicitly truncated into a float. This means that the calculation will be slower (though more accurate) than it would have been if you had written 2.0f or 2.
Had you written 2, the constant would be of int type, which would be promoted to a float, and the calculation would have been done with "float precision". A good compiler would warn you about this promotion.
Read more about the "usual arithmetic conversion" rules here:
http://msdn.microsoft.com/en-us/library/3t4w2bkb%28v=vs.80%29.aspx
Because by unsuffixed floating-point literals are doubles, and rounding means that even small literals can take on different values when rounded to float and double. This can be observed in the following example:
float f=0.67;
if(f == 0.67)
printf("yes");
else
printf("no");
This will output no, because 0.67 has a different value when rounded to float than it does when rounded to double. On the other hand:
float f=0.67;
if(f == 0.67f)
printf("yes");
else
printf("no");
outputs yes.
The suffix can be specified using either upper or lowercase letters.
Try this also:
printf(" %u %u\n", sizeof(.67f), sizeof(.67));
Check #codepade
3.00 is a double, 3.00f is a float.
Adding few more combination of comparisons between float and double data types.
int main()
{
// Double type constant(3.14) converts to Float type by
// truncating it's bits representation
float a = 3.14;
// Problem: float type 'a' promotes to double type and the value
// of 'a' depends on how many bits added to represent it.
if(a == 3.14)
std::cout<<"a: Equal"<<std::endl;
else
std::cout<<"a: Not Equal"<<std::endl;
float b = 3.14f; // No type conversion
if(b == 3.14) // Problem: Float to Double conversion
std::cout<<"b: Equal"<<std::endl;
else
std::cout<<"b: Not Equal"<<std::endl;
float c = 3.14; // Double to Float conversion (OK even though is not a good practice )
if(c == 3.14f) // No type conversion
std::cout<<"c: Equal"<<std::endl; // OK
else
std::cout<<"c: Not Equal"<<std::endl;
float d = 3.14f;
if(d == 3.14f)
std::cout<<"d: Equal"<<std::endl; // OK
else
std::cout<<"d: Not Equal"<<std::endl;
return 0;
}
Output:
a: Not Equal
b: Not Equal
c: Equal
d: Equal
That's because the default type of a
floating point numeric literal - the
characters 3.00 is double not float.
To make this compile you have to add
the suffix f (or F).
Often the difference isn't important, as the compiler will convert the double constant into a float anyway. However, consider this:
template<class T> T min(T a, T b)
{
return (a < b) ? a : b;
}
float x = min(3.0f, 2.0f); // will compile
x = min(3.0f, 2); // compiler cannot deduce T type
x = min(3.0f, 2.0); // compiler cannot deduce T type

Resources