This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++17 status.

### 2403. `stof()` should call `strtof()` and `wcstof()`

Section: 23.4.5 [string.conversions] Status: C++17 Submitter: Stephan T. Lavavej Opened: 2014-06-14 Last modified: 2017-07-30

Priority: 2

View all other issues in [string.conversions].

View all issues with C++17 status.

Discussion:

`stof()` is currently specified to call `strtod()`/`wcstod()` (which converts the given string to `double`) and then it's specified to convert that `double` to `float`. This performs rounding twice, which introduces error. Here's an example written up by James McNellis:

Consider the following number `X`:

>     1.999999821186065729339276231257827021181583404541015625 (X)

This number is exactly representable in binary as:

>     1.111111111111111111111101000000000000000000000000000001
>     * ^1st                  ^23rd                        ^52nd

I've marked the 23rd and 52nd fractional bits. These are the least significant bits for `float` and `double`, respectively.

If we convert this number directly to `float`, we take the 23 most significant bits:

>     1.11111111111111111111110

The next bit is a one and the tail is nonzero (the 54th fractional bit is a one), so we round up. This gives us the correctly rounded result:

>     1.11111111111111111111111

So far so good. But... If we convert `X` to `double`, we take the 52 most significant bits:

>     1.1111111111111111111111010000000000000000000000000000 (Y)

The next bit is a zero, so we round down (truncating the value). If we then convert `Y` to `float`, we take its 23 most significant bits:

>     1.11111111111111111111110

The next bit is a one and the tail is zero, so we round to even (leaving the value unchanged). This is off by 1ulp from the correctly rounded result.

[2014-06 Rapperswil]

Marshall Clow will look at this.

[Urbana 2014-11-07: Move to Ready]

Proposed resolution:

This wording is relative to N3936.

1. Change 23.4.5 [string.conversions] p4+p6 as indicated:

   >     float stof(const string& str, size_t* idx = 0);
   >     double stod(const string& str, size_t* idx = 0);
   >     long double stold(const string& str, size_t* idx = 0);

   > > -4- Effects: the first two These functions call `strtof(str.c_str(), ptr)`, `strtod(str.c_str(), ptr)`, and the third function calls `strtold(str.c_str(), ptr)`, respectively. Each function returns the converted result, if any. […]

   > > […]

   > > -6- Throws: `invalid_argument` if `strtof`, `strtod`, or `strtold` reports that no conversion could be performed. Throws `out_of_range` if `strtof`, `strtod`, or `strtold` sets `errno` to `ERANGE` or if the converted value is outside the range of representable values for the return type.

2. Change 23.4.5 [string.conversions] p11+p13 as indicated:

   >     float stof(const wstring& str, size_t* idx = 0);
   >     double stod(const wstring& str, size_t* idx = 0);
   >     long double stold(const wstring& str, size_t* idx = 0);

   > > -11- Effects: the first two These functions call `wcstof(str.c_str(), ptr)`, `wcstod(str.c_str(), ptr)`, and the third function calls `wcstold(str.c_str(), ptr)`, respectively. Each function returns the converted result, if any. […]

   > > […]

   > > -13- Throws: `invalid_argument` if `wcstof`, `wcstod`, or `wcstold` reports that no conversion could be performed. Throws `out_of_range` if `wcstof`, `wcstod`, or `wcstold` sets `errno` to `ERANGE`.