Created on 2014-06-14.00:00:00 last changed 89 months ago
Proposed resolution:
This wording is relative to N3936.
Change [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: 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.the first twoThese functions call strtof(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. […]
Change [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: 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.the first twoThese functions call wcstof(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. […]
[ Urbana 2014-11-07: Move to Ready ]
[ 2014-06 Rapperswil ]
Marshall Clow will look at this.
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.
History | |||
---|---|---|---|
Date | User | Action | Args |
2017-07-30 20:15:43 | admin | set | status: wp -> c++17 |
2015-05-22 18:31:21 | admin | set | status: ready -> wp |
2014-11-08 16:43:57 | admin | set | messages: + msg7174 |
2014-11-08 16:43:57 | admin | set | status: new -> ready |
2014-06-29 12:55:08 | admin | set | messages: + msg7087 |
2014-06-14 19:06:15 | admin | set | messages: + msg7037 |
2014-06-14 00:00:00 | admin | create |