2010-09-21 4 views
6

У меня есть простой код, который сравнивает два значения float, чтобы проиллюстрировать проблему, которую я вижу при оптимизации GCC, и надеюсь, что кто-то может помочь мне понять, почему вывод, который он производит, отличается при некоторых повторяющиеся обстоятельства.GCC Обработка поплавков по-разному на разных уровнях оптимизации

Во-первых, я знаю, что сравнивать значения float с ==, потому что вы можете отключиться от небольшого количества в мантиссе, однако в моем примере это не так. Проблема, которую я имею, - это выходные изменения, основанные на двух факторах. 1) флаг оптимизации, который я передаю, и 2) если я раскомментирую строку std :: cout.

Почему код GCC производит работу по-разному под -O2? Почему код, скомпилированный под -O2, работает, если я раскомментирую печать?

Вот код, я тестирование:

#include <iostream> 

const float ft_to_m   = (float)0.3048; 
const float m_to_ft   = (float)3.28083989501; 


float FeetToKilometers(float & Feet) { 
    float Kilometers; 
    Kilometers = (ft_to_m * Feet)/1000.; 
    return Kilometers; 
} 

int main(void) 
{ 
    float feet = 20000.; 
    float old_val = 0; 
    float new_val = FeetToKilometers(feet); 
    float diff_val = 0; 

    int *old_int = reinterpret_cast<int*>(&old_val); 
    int *new_int = reinterpret_cast<int*>(&new_val); 

    for (int i=0; i<2; i++) 
    { 

    new_val = FeetToKilometers(feet); 
    diff_val = old_val-new_val; 

    //std::cout << "Random COUT that makes this work" << std::endl; 

     if(old_val==new_val) 
    { 
      std::cout << "old_val==new_val" << std::endl; 
     std::cout << std::hex << *old_int << "," << std::hex << *new_int << std::endl; 
      std::cout << "diff_val = " << diff_val <<std::endl; 
    } 
     else 
     { 
      std::cout << "old_val!=new_val" <<std::endl; 
     std::cout << std::hex << *old_int << "," << std::hex << *new_int << std::endl; 
      std::cout << "diff_val = " << diff_val <<std::endl; 
      old_val=FeetToKilometers(feet); 
     } 
    } 

    return 0; 
} 

При компиляции на Linux/Cygwin с -O0, -O1 и -O3 (г ++ -О test.cpp), я получаю следующий результат:


$ ./a.exe
old_val! = new_val
0,40c3126f
diff_val = -6,096
old_val == new_val
40c3126f, 40c3126f
diff_val = 0


Это выход правильно, вы можете увидеть биты для поплавков (new_val и old_val) идентичны. Когда я компилирую с флагом -O2 (г ++ -O2 test.cpp) Я получаю следующее:


$ ./a.exe
old_val = new_val
0,40c3126f
diff_val = -6,096
old_val! = new_val
40c3126f, 40c3126f
diff_val = 1.19209e-07


Я считаю, что этот выход неправильный. Несмотря на то, что эти два значения являются одинаковыми бит мудрый, вычитая их, а проверка == показывает, что они разные. Если бы я тогда раскомментируйте станд :: соиЬ линия, и восстановить с флагом -O2 (г ++ -O2 test.cpp) Я получаю следующее:


$ ./a.exe
Случайные COUT что делает эту работу
old_val! = new_val
0,40c3126f
diff_val = -6.096
Случайные COUT, что делает эту работу
old_val == new_val
40c3126f, 40c3126f
diff_val = 1.19209e-07


Это верно в том, что old_val == new_val, даже несмотря на то, вычитание все еще показывает небольшую разницу.

Этот код также работает под -O2, если ноги в 2000, вместо 20000.

Может кто-нибудь объяснить, почему скомпилированный код ведет себя, как это? Я хочу знать, почему 2-битные идентичные значения float нельзя сравнивать с ==.

GCC версия 3.4.4

ответ

10

Уровень оптимизации и окружающие код могут повлиять ли значение, используемое при расчете diff_val в настоящее время извлекается из памяти, или из регистров. Процессор может использовать 80-битные внутренние регистры с плавающей запятой в одном случае, а 32-разрядные плавающие значения из памяти в другом случае, что дает неожиданные результаты.

Еще одна причина, по которой избежать использования == для сравнения с плавающей запятой!

+2

+1. Это (почти определенно) проблема. Компиляция с опцией '-ffloat-store' дает согласованные результаты независимо от уровня оптимизации. – eldarerathis

+0

Итак, может быть, я нооб, но как вы должны делать сравнения с плавающей запятой? <= and > =? Просто ссылки на соответствующую информацию было бы достаточно. Благодарю. –

+0

@Robert: 'fabs (a-b)