С++ Странное поведение с двойным comparaison
Я разрабатываю unit test для своего приложения, но я столкнулся со странной проблемой, которую я не понимаю.
Код:
double res = BytesTool::convertSize(1, BytesTool::Byte, BytesTool::KiloByte);
double tmp = pow((double)1000, -1);
QVERIFY(res == tmp);
Я компилирую с Linux-машины (хост 64 бита) для Linux 64bits с gcc (хост 64 бит) и перекрестная компиляция для Windows 32bits с компилятором Linux mingw32.
Программа отлично работает (успех утверждения) с компиляцией Linux в режиме отладки и выпуска.
Для версии Windows он отлично работает в отладочной версии, но не для версии выпуска; утверждение терпит неудачу.
Странная часть: если я вставляю трассировку, тест работает в Windows:
double res = BytesTool::convertSize(1, BytesTool::Byte, BytesTool::KiloByte);
printf("test");
double tmp = pow((double)1000, -1);
QVERIFY(res == tmp); // Is TRUE when printf("test") is present, FALSE otherwise
Я потерялся, и я действительно не понимаю, что происходит. Почему printf
заставляет его работать?
Благодарим за помощь.
Ответы
Ответ 1
printf заставит его работать, потому что число с плавающей запятой будет преобразовано из внутреннего 80-битного представления FPU (предполагая x86 "старое" математическое представление) в 64-разрядный, который сохраняется в двойном.
Причиной этого является то, что значение регистра должно быть перенесено в стек при вызове другой функции (опять же, принимая условные условные обозначения FPU в стиле x86), что приведет к округлению до 64 бит точности.
Ваши другие компиляции, скорее всего, работают, потому что они используют математику SSE2 +, которая имеет собственный 64-битный тип с плавающей запятой.
==
проверяет, что поплавки идентичны, что почти никогда не является правильным для чисел с плавающей запятой.
В этом случае это происходит не потому, что внутреннее представление ЦП отличается от того, которое хранится в двойном.
При сравнении чисел с плавающей запятой всегда проверяйте, достаточно ли они близки друг к другу, а не равны.
#include <math.h>
QVERIFY( fabs(res-tmp) < DBL_EPSILON )
Ответ 2
Это будет битком. Double работает так же, как и с плавающей запятой, и это объясняет это хорошо https://www.youtube.com/watch?v=PZRI1IfStY0