stof()
should call strtof()
and wcstof()
Section: 27.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:
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.
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.
Change 27.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:
[…] -6- Throws:the first twoThese functions callstrtof(str.c_str(), ptr)
,strtod(str.c_str(), ptr)
, andthe third function callsstrtold(str.c_str(), ptr)
, respectively. Each function returns the converted result, if any. […]invalid_argument
ifstrtof
,strtod
, orstrtold
reports that no conversion could be performed. Throwsout_of_range
ifstrtof
,strtod
, orstrtold
setserrno
toERANGE
or if the converted value is outside the range of representable values for the return type.
Change 27.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:
[…] -13- Throws:the first twoThese functions callwcstof(str.c_str(), ptr)
,wcstod(str.c_str(), ptr)
, andthe third function callswcstold(str.c_str(), ptr)
, respectively. Each function returns the converted result, if any. […]invalid_argument
ifwcstof
,wcstod
, orwcstold
reports that no conversion could be performed. Throwsout_of_range
ifwcstof
,wcstod
, orwcstold
setserrno
toERANGE
.