Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is literal double to float conversion equal to float literal?

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?

like image 984
Jan15 Avatar asked Dec 14 '22 12:12

Jan15


2 Answers

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.

like image 146
Patricia Shanahan Avatar answered Dec 28 '22 23:12

Patricia Shanahan


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.

like image 27
aka.nice Avatar answered Dec 29 '22 00:12

aka.nice