The canonical example used for explaining the binary vs decimal representation of floating points is the value 0.3
:
float asFloat = 0.3; // <-- 0.300000012
double asDouble = 0.3; // <-- 0.29999999999999999
double asCastedDouble = static_cast<double>( asFloat ); // <-- 0.30000001192092896
asFloat
and asDouble
are the closest possible binary representation possible of the literal 0.3
. A naïve look might be surprised at the value of asCastedDouble
, but then we remember that it’s the closest representation of the float value, not of the literal, so that makes sense. I do wonder, however, why the casted double representation is not identical to the float representation (which is already in binary) with added zero bits in the mantissa, which in decimal would translate to 0.300000011200000000
, but that is a separate question.
Consider now a second example for a different literal:
float asFloat2 = -0.488730401; // <-- -0.488730401
double asDouble2 = -0.488730401; // <-- -0.48873040099999998
double asCastedDouble2 = static_cast<double>( asFloat2 ); // <-- -0.48873040080070496
This literal happens to be accurately representable in binary, hence asFloat2
is the same as our literal value. Just like in the last example, I wonder why asDouble2
is “less” accurate than asFloat2
instead of being identical with extra zero bits in the mantissa, but I’ll let it slide.
The question is now: why is asCastedDouble2
the value that it is? It is not the same setup as the previous example, as in there we had a precision error introduced in the float, which was then carried into the double. In this case, however, the float value is identical to the literal, so where does the value of as asCastedDouble2
come from? It is clearly not the closest binary representation possible, since asDouble2
shows us a closer representation?
So I guess my question is twofold:
I do wonder, however, why the casted double representation is not identical to the float representation
They are identical, you just don't print enough digits.
#include <iomanip>
#include <iostream>
int main()
{
float asFloat = 0.3;
double asDouble = 0.3;
double asCastedDouble = static_cast<double>( asFloat );
std::cout << std::setprecision(1000);
std::cout << asFloat << '\n'; // 0.300000011920928955078125
std::cout << asDouble << '\n'; // 0.299999999999999988897769753748434595763683319091796875
std::cout << asCastedDouble << '\n'; // 0.300000011920928955078125
}
Consider now a second example ... This literal happens to be accurately representable in binary
No it isn't. You're not printing enough digits.
#include <iomanip>
#include <iostream>
int main()
{
float asFloat = -0.488730401;
double asDouble = -0.488730401;
double asCastedDouble = static_cast<double>( asFloat );
std::cout << std::setprecision(1000);
std::cout << asFloat << '\n'; // -0.4887304008007049560546875
std::cout << asDouble << '\n'; // -0.4887304009999999809821247254149056971073150634765625
std::cout << asCastedDouble << '\n'; // -0.4887304008007049560546875
}