С++ Странное поведение с двойным 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