C ++: двойники, точность, виртуальные машины и GCC

У меня есть следующий фрагмент кода:

#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.

21
задан Seki 14 June 2015 в 09:46
поделиться