Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

strtof = strtod followed by cast?

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?

like image 940
rwallace Avatar asked Aug 01 '19 11:08

rwallace


1 Answers

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 floats. Rounding directly to float gets you the nearest float, and going through the nearest double produces the other float.

like image 126
Pascal Cuoq Avatar answered Nov 07 '22 18:11

Pascal Cuoq