The simple answer is that 0.1 is not exactly represent-able within the precision of float and has to be truncated to the precision of float when assigned. For the comparison, the float is converted to double and compared with the literal 0.1 which was truncated to the precision of double.
If you change to
double
you will get
True
, as both will be truncated to the same value.
If you change to a number represent-able within the mantissa bits of the float (0.5 or 0.25 or 0.75 etc) you will also get
True
.
The detail is that
float x = 0.1
is truncated to 23 bits of the float, and then expanded to the 52 bits of the double for the comparison, while the literal 0.1 is represented as 52 bits with no truncation to 23 bits along the way.
With some old-style casting you can prove:
1 2 3 4 5 6
|
cout << std::hex << "x =" << *(int *)&x << endl; // sizeof(int) == sizeof(float) on my machine
double d=0.1;
cout << std::hex << "0.1=" << *(long long *)& d << endl; // sizeof(double) == sizeof(long long) on my machine
d = (float)0.1;
cout << std::hex << "d =" << *(long long *)& d << endl;
| |
x =3dcccccd
0.1=3fb999999999999a
d =3fb99999a0000000
|
So the float becomes a double by adding zeros to the extra bits of the mantissa. In this case they will not be equal.
When using a number exactly represent-able by float (within the mantissa bits), no truncation takes place, and the float converted to double will be the same as the literal:
x =3ec00000
0.375=3fd8000000000000
d =3fd8000000000000 |
Notice all the trailing zeros. In this case they will be equal.
Ref:
http://en.wikipedia.org/wiki/Single-precision_floating-point_format
http://en.wikipedia.org/wiki/Double-precision_floating-point_format
As mentioned above, exact comparison of floats and doubles is to be avoided, and is non-portable.