десятичная ошибка в std :: strtod () в Visual Studio 2015, 64-разрядная версия

std::strod() преобразует строку в двойную Но в одном конкретном случае есть небольшая десятичная ошибка. Эта ошибка также может быть замечена с atof() а также sscanf(), Ошибка возникает только если все следующие условия выполняются:

  • Visual Studio 2015 (или VS 2015, обновление 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() опять точно, так res3 0,5

Обратите внимание, что некоторые десятичные числа не могут быть представлены точно. Но некоторые цифры могут, например, 2,5, 0,5 и 0,375, но все они получают ошибку округления в приведенном выше примере.

Странно, не правда ли?

Я делаю что-то не так, или это ошибка в стандартной библиотеке Visual Studio?

2

Решение

Благодаря ссылке от Адриана Маккарти, я нашел обходной путь: использовать
fesetround() вместо _controlfp_s():

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

fesetround() был представлен в VS2015.
Я сообщу об ошибке в Microsoft.
Можно также использовать #if _MSC_VER == 1900 && defined(_WIN64) чтобы быть более точным, так как ошибка не существует для 32-битных целей.

0

Другие решения

Это не ошибка. Это особенность!

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

0

По вопросам рекламы [email protected]