Reputation: 33
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?
Upvotes: 2
Views: 136
Reputation: 23832
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.
Upvotes: 2
Reputation: 7726
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
.
Upvotes: 2
Reputation: 123578
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
.
Upvotes: 1
Reputation: 108988
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
Upvotes: 1
Reputation: 35164
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
Upvotes: 0
Reputation: 225007
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.
Upvotes: 5
Reputation: 13189
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
Upvotes: 1