Suppose you have a string like "0.1" that can be only approximately represented as a binary floating point number, and you want to convert it to single precision floating point. This can be done as
strtof(s, 0);
or
(float)strtod(s, 0);
Intuitively, these should give the same result, but is intuition correct in all cases? Or are there any edge cases in which the second form, by doing the rounding twice, gives a slightly different result from the first form?
The C standard's specification of strtod
and strtof
is underspecified. It leaves room for the possibility that strtof
returns (float)strtod
always, very often or never. (This paragraph refers to another section of the standard that contains that paragraph, which says “the result is either the nearest representable value, or the larger or smaller representable value immediately adjacent to the nearest representable value, chosen in an implementation-defined manner”).
The typical implementations of strtod
and strtof
return respectively the nearest double
and the nearest float
to the decimal representation passed to them. When these functions behave this way, then strtof(s, 0)
is almost always identical to (float)strtod(s, 0)
. The decimal representations for which they are not identical are said to exhibit a double-rounding problem, because rounding the decimal representation first to double
and then to float
produces a different result than rounding directly to float
. Note that when this happens, the strtof
result is the more exact one. The intermediate rounding made the error slightly more than half a ULP rather than slightly less than half a ULP.
One example of decimal representation with a double-rounding problem when going through double
before converting to float
is 1.01161128282547
(taken from this quiz). The nearest double
is exactly halfway between two float
s. Rounding directly to float
gets you the nearest float
, and going through the nearest double
produces the other float
.