2

std::strod() converts string to double. But in one particular case, there is a tiny decimal error. This error can also be seen with atof() and sscanf(). The error only occurs if all the following conditions are met:

  • Visual Studio 2015 (or VS 2015 update 1)
  • Build for 64 bit (x64)
  • Call to _controlfp_s() to set "rounding towards minus infinity"
  • The number has a decimal part, e.g. 0.5 or 2.5 (not an integer)

(I have only tested on 64 bit Windows 8.1 Enterprise) A simple example is here:

#include <string>

inline double fromString(const std::string& s) {
   size_t idx;
   return std::stod(s, &idx);
}

int main()
{
   double res1 = fromString("0.5");
   unsigned tmp;
   _controlfp_s(&tmp, RC_DOWN, MCW_RC);
   double res2 = fromString("0.5");
   _controlfp_s(&tmp, RC_NEAR, MCW_RC);
   double res3 = fromString("0.5");
}

std::stod() is calling std::calling strtod() in stdlib.h. res1 will be exactly 0.5, but res2 will be 0.50000000000000011

_controlfp_s(&tmp, RC_DOWN, MCW_RC); controls rounding errors, in this case it is set to round towards minus infinity. If it is set back to default with _controlfp_s(&tmp, RC_NEAR, MCW_RC); then strod() is exact again, so res3 is 0.5

Note that some decimal numbers cannot be represented exactly. But some numbers can, e.g. 2.5, 0.5, and 0.375, but they all get a rounding error in the above example.

Weird, isn't it?

Am I doing something wrong, or is this a bug in Visual Studio's standard library?

Johan
  • 31
  • 3
  • 3
    [What Every Computer Scientist Should Know About Floating-Point Arithmetic](https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) – Martin York Dec 07 '15 at 19:01
  • You have got 15 correct decimals, which is the maximum you can expect from a `double`. – Bo Persson Dec 07 '15 at 19:11
  • 1
    When you start messing around with FPU control word, all bets concerning standard library functions are off. Hard to call it a "bug", you're simply operating outside the design. – Ben Voigt Dec 07 '15 at 19:11
  • Almost every version of strtod has some bugs. Here are some examples for VC++2015: http://www.exploringbinary.com/visual-c-plus-plus-strtod-still-broken/ – Adrian McCarthy Dec 07 '15 at 22:11
  • @BenVoigt: Does Microsoft state somewhere that they do not support change og FPU control word? Or is it just your expectation? – Johan Dec 09 '15 at 01:18
  • @BenVoigt: At [The Visual C++ Team Blog](http://blogs.msdn.com/b/vcblog/archive/2014/06/18/crt-features-fixes-and-breaking-changes-in-visual-studio-14-ctp1.aspx) they state that "The FLT_ROUNDS macro is now dynamic and correctly reflects the current rounding mode". To me, that indicates that MS at least has the good intention of handling this correctly. – Johan Dec 09 '15 at 01:28
  • @AdrianMcCarthy: Thank you for the link. Very useful information. – Johan Dec 09 '15 at 01:29

2 Answers2

0

Thanks to the link from Adrian McCarthy, I found a work-around: To use fesetround() instead of _controlfp_s():

#if _MSC_VER == 1900
   //Visual Studio 2015
   fesetround(FE_DOWNWARD);
#else
   _controlfp_s(&tmp, RC_DOWN, MCW_RC);
#endif

fesetround() was introduced in VS2015. I will report the bug to Microsoft. One could also use #if _MSC_VER == 1900 && defined(_WIN64) to be more precise, since the bug is not there for 32 bit targets.

Johan
  • 31
  • 3
0

This is not a bug. It's a feature!

https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

Gianluca Ghettini
  • 11,129
  • 19
  • 93
  • 159
  • Hi Gianluca, Loke Astari already posted that link. Could you be a bit more specific, why you think this bug is a feature? – Johan Dec 10 '15 at 10:15