2

std::strod()文字列を double に変換します。しかし、ある特定のケースでは、わずかな小数エラーがあります。このエラーは、 および にも表示されatof()ますsscanf()。このエラーは、次の条件がすべて満たされている場合にのみ発生します。

  • Visual Studio 2015 (または VS 2015 update 1)
  • 64 ビット (x64) 用にビルド
  • を呼び出して_controlfp_s()「マイナス無限大への丸め」を設定します
  • 数値には小数部分があります (例: 0.5 または 2.5 (整数ではありません))。

(64 ビットの Windows 8.1 Enterprise でのみテストしました) 簡単な例を次に示します。

#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()std::calling strtod()stdlib.h を呼び出しています。res1正確に 0.5 にres2なりますが、0.50000000000000011 になります

_controlfp_s(&tmp, RC_DOWN, MCW_RC);丸め誤差を制御します。この場合、負の無限大に向かって丸めるように設定されています。_controlfp_s(&tmp, RC_NEAR, MCW_RC);デフォルトに戻すとstrod()、再び正確になり、res30.5になります。

一部の 10 進数は正確に表現できないことに注意してください。ただし、2.5、0.5、0.375 などの一部の数値は使用できますが、上記の例ではすべて丸め誤差が発生します。

変ですね。

何か間違っているのでしょうか、それとも Visual Studio の標準ライブラリのバグですか?

4

2 に答える 2

0

Adrian McCarthy からのリンクのおかげで、次の回避策を見つけまし fesetround()_controlfp_s()

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

fesetround()VS2015で導入されました。マイクロソフトにバグを報告します。#if _MSC_VER == 1900 && defined(_WIN64)バグは 32 ビット ターゲットには存在しないため、より正確に使用することもできます。

于 2015-12-10T08:26:03.323 に答える
0

これはバグではありません。特徴です!

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

于 2015-12-10T09:24:48.963 に答える