У меня есть следующий фрагмент кода:
#include <cstdio>
int main()
{
if ((1.0 + 0.1) != (1.0 + 0.1))
printf("not equal\n");
else
printf("equal\n");
return 0;
}
При компиляции с O3 с использованием gcc (4.4,4.5 и 4.6) и при исходном запуске (ubuntu 10.10) он выводит ожидаемый результат «равно».
Однако тот же код при компиляции, как описано выше, и запуске на виртуальной машине (ubuntu 10.10, образ виртуального бокса), выводит «не равно» - это тот случай, когда установлены флаги O3 и O2, но не O1 и ниже. При компиляции с помощью clang (O3 и O2) и запуске на виртуальной машине я получаю правильный результат.
Я понимаю, что 1.1 не может быть правильно представлен с помощью double, и я прочитал «Что должен знать каждый компьютерный ученый об арифметике с плавающей запятой» , поэтому, пожалуйста, не указывайте мне здесь, это кажется быть какой-то оптимизацией, которую делает GCC, которая почему-то не работает на виртуальных машинах.
Есть идеи?
Примечание. В стандарте C ++ говорится, что продвижение типов в таких ситуациях зависит от реализации. Может быть, GCC использует более точное внутреннее представление, которое, когда применяется тест неравенства, остается верным - из-за дополнительных точность?
ОБНОВЛЕНИЕ1: Следующая модификация приведенного выше фрагмента кода теперь дает правильный результат. Кажется, что в какой-то момент по какой-то причине GCC отключает управляющее слово с плавающей запятой.
#include <cstdio>
void set_dpfpu() { unsigned int mode = 0x27F; asm ("fldcw %0" : : "m" (*&mode));
int main()
{
set_dpfpu();
if ((1.0 + 0.1) != (1.0 + 0.1))
printf("not equal\n");
else
printf("equal\n");
return 0;
}
ОБНОВЛЕНИЕ 2: Для тех, кто спрашивает о природе константного выражения кода, я изменил его следующим образом, и все еще не работает при компиляции с помощью GCC. - но я предполагаю, что оптимизатор также может превратить следующее в выражение const.
#include <cstdio>
void set_dpfpu() { unsigned int mode = 0x27F; asm ("fldcw %0" : : "m" (*&mode));
int main()
{
//set_dpfpu(); uncomment to make it work.
double d1 = 1.0;
double d2 = 1.0;
if ((d1 + 0.1) != (d2 + 0.1))
printf("not equal\n");
else
printf("equal\n");
return 0;
}
ОБНОВЛЕНИЕ 3 Разрешение: Обновление виртуального бокса до версии 4.1.8r75467 устранило проблему. Однако остается одна проблема, а именно: почему сработала сборка clang.