开发者

GCC Handling Float comparison differently at different Optimization Levels

开发者 https://www.devze.com 2023-01-16 21:48 出处:网络
开发者_如何学运维I have some simple code that is comparing two float values to illustrate a problem I see with GCC\'s optimization and am hoping someone can help me figure out why the output it produc

开发者_如何学运维I have some simple code that is comparing two float values to illustrate a problem I see with GCC's optimization and am hoping someone can help me figure out why the output it produces is different under some repeatable circumstances.

First, I know it's bad to compare float values with == because you can be off by some very small amount in the mantissa, however that is not the case in my example. The problem I have is the output changes based on 2 factors. 1) the optimization flag I pass in, and 2) if I uncomment the std::cout line.

Why does the code GCC produce run differently under -O2? Why does the code compiled under -O2 work if I uncomment the print?

Here is the code I am testing:

#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;
}

When compiled on linux/cygwin with -O0, -O1, and -O3 ( g++ -O test.cpp ), I get the following output:


$ ./a.exe

old_val!=new_val

0,40c3126f

diff_val = -6.096

old_val==new_val

40c3126f,40c3126f

diff_val = 0


That output is correct, you can see the bits for the floats (new_val and old_val) are identical. When I compile with the -O2 flag ( g++ -O2 test.cpp ) I get the following:


$ ./a.exe

old_val!=new_val

0,40c3126f

diff_val = -6.096

old_val!=new_val

40c3126f,40c3126f

diff_val = 1.19209e-07


I would consider this output wrong. Even though the two values are the same bit wise, subtracting them and the == check indicate they are different. If I then uncomment the std::cout line, and rebuild with the -O2 flag ( g++ -O2 test.cpp ) I get the following:


$ ./a.exe

Random COUT that makes this work

old_val!=new_val

0,40c3126f

diff_val = -6.096

Random COUT that makes this work

old_val==new_val

40c3126f,40c3126f

diff_val = 1.19209e-07


This is correct in that old_val == new_val, even though the subtraction still shows a slight difference.

This code also works under -O2 if feet is 2000, instead of 20000.

Can anyone explain why the compiled code is behaving like this? I want to know why 2 bit identical float values cannot be compared with ==.

gcc version 3.4.4


The optimization level and surrounding code may affect whether the values used in the diff_val calculation are being fetched from memory, or from registers. The processor may be using 80-bit internal floating point registers in one case, and 32-bit floating point values from memory in the other case, giving unexpected results.

Yet another reason to avoid using == for floating point comparisons!

0

精彩评论

暂无评论...
验证码 换一张
取 消