У меня есть простой код, который сравнивает два значения с плавающей запятой, чтобы проиллюстрировать проблему, которую я вижу с оптимизацией GCC, и надеюсь, что кто-то может помочь мне выяснить, почему это результат производит разные при некоторых повторяющихся обстоятельствах.
Во-первых, я знаю, что сравнивать значения с плавающей запятой с == - это плохо, потому что в мантиссе может возникнуть очень небольшое отклонение, однако в моем примере это не так. Проблема, с которой я сталкиваюсь, заключается в изменении вывода на основе двух факторов. 1) флаг оптимизации, который я передаю, Почему код, скомпилированный под -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 (g ++ -O 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 (g ++ -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
Я считаю этот вывод неправильным. Несмотря на то, что эти два значения одинаковы , их вычитание и проверка == показывают, что они различны. Если я затем раскомментирую строку std :: cout и перестрою с флагом -O2 (g ++ -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, если foot равен 2000, а не 20000.
Может ли кто-нибудь объяснить, почему скомпилированный код ведет себя так? Я хочу знать, почему 2-битные одинаковые значения с плавающей запятой нельзя сравнивать с ==.
gcc версии 3.4.4