Can there be a difference in bit-representation between a direct assignment of a floating point literal float x = 3.2f;
and a double
implicitly converted to a float float x2 = 3.2;
?
I.e. is
#define EQUAL(FLOAT_LITERAL)\
FLOAT_LITERAL##f == static_cast<float>(FLOAT_LITERAL)
EQUAL(3.2) && EQUAL(55.6200093490) // etc ...
true
for all floating point literals?
I ask this question, because clang or gcc do not complain about narrowing conversions if numbers are in the value range of float:
Warning is enabled with -Wnarrowing
:
float f {3.422222222222222222222222222222246454}; // no warning/ error although it should definitely lose precision
float f2 {static_cast<double>(std::numeric_limits<float>::max()) + 1.0}; // no warning/ error
float f3 {3.5e38}; // error: narrowing conversion of '3.5e+38' from 'double' to 'float' inside { } [-Wnarrowing]
It is great that the compiler does actual range checks, but is that sufficient?
Assuming IEEE 754, float as 32 bit binary, double as 64 bit binary.
There are decimal fractions that round differently, under IEEE 754 round-to-nearest rules, if converted directly from decimal to float from the result of first converting from decimal to double and then to float.
For example, consider 1.0000000596046447753906250000000000000000000000000001
1.000000059604644775390625 is exactly representable as a double and is exactly half way between 1.0 and 1.00000011920928955078125, the value of the smallest float greater than 1.0. 1.0000000596046447753906250000000000000000000000000001 rounds up to 1.00000011920928955078125 if converted directly, because it is greater than the mid point. If it is first converted to 64 bit, round to nearest takes it to the mid point 1.000000059604644775390625, and then round half even rounds down to 1.0.
The answer given by Patricia is correct. But we generally don't type such number, so maybe it's not a problem... Unless it happens with some shorter decimal literals?
I have illustrated that once in the comments following that answer Count number of digits after `.` in floating point numbers?
The decimal value 7.038531e-26 is approximately 0x1.5C87FAFFFFFFFCE4F6700...p-21 the nearest double is 0x1.5C87FB0000000p-21 and the nearest float is 0x1.5C87FAp-21.
Note that 0x1.5C87FA0000000p-21 is the nearest double to 7.038530691851209e-26
So yes, there can be a double-rounding problem (round off error twice in the same direction) with a relatively short literal...
float x = 7.038531e-26f;
and float y = 7.038531e-26;
should be two different numbers if the compiler rounds the literals correctly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With