title: GCC Handling Float comparison differently at different Optimization Levels
body: <p>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.  </p>
  
  <p>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.</p>
  
  <p>Why does the code GCC produce run differently under -O2?
  Why does the code compiled under -O2 work if I uncomment the print?</p>
  
  <p>Here is the code I am testing:</p>
  
  <pre><code>#include &lt;iostream&gt;
  
  const float ft_to_m          =  (float)0.3048; 
  const float m_to_ft          =  (float)3.28083989501;
  
  
  float FeetToKilometers( float &amp; 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&lt;int*&gt;(&amp;old_val);
      int *new_int = reinterpret_cast&lt;int*&gt;(&amp;new_val);
  
      for (int i=0; i&lt;2; i++)
      {
  
      new_val = FeetToKilometers(feet );
      diff_val = old_val-new_val;
  
      //std::cout &lt;&lt; "Random COUT that makes this work" &lt;&lt; std::endl;
  
          if(old_val==new_val)
      {
               std::cout &lt;&lt; "old_val==new_val" &lt;&lt; std::endl;
           std::cout &lt;&lt; std::hex &lt;&lt; *old_int &lt;&lt; "," &lt;&lt; std::hex &lt;&lt; *new_int &lt;&lt; std::endl;
               std::cout &lt;&lt; "diff_val = " &lt;&lt; diff_val &lt;&lt;std::endl;
      }
          else
          {
              std::cout &lt;&lt; "old_val!=new_val" &lt;&lt;std::endl;
          std::cout &lt;&lt; std::hex &lt;&lt; *old_int &lt;&lt; "," &lt;&lt; std::hex &lt;&lt; *new_int &lt;&lt; std::endl;
              std::cout &lt;&lt; "diff_val = " &lt;&lt; diff_val &lt;&lt;std::endl;
              old_val=FeetToKilometers(feet);
          }
      }
  
      return 0;
  }
  </code></pre>
  
  <p>When compiled on linux/cygwin with -O0, -O1, and -O3 ( g++ -O test.cpp ), I get the following output:</p>
  
  <hr>
  
  <blockquote>
    <p>$ ./a.exe<br>
    old_val!=new_val<br>
    0,40c3126f<br>
    diff_val = -6.096<br>
    old_val==new_val<br>
    40c3126f,40c3126f<br>
    diff_val = 0  </p>
  </blockquote>
  
  <hr>
  
  <p>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:</p>
  
  <hr>
  
  <blockquote>
    <p>$ ./a.exe<br>
    old_val!=new_val<br>
    0,40c3126f<br>
    diff_val = -6.096<br>
    old_val!=new_val<br>
    40c3126f,40c3126f<br>
    diff_val = 1.19209e-07  </p>
  </blockquote>
  
  <hr>
  
  <p>I would consider this output wrong.  Even though the two values are the <strong>same</strong> 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:</p>
  
  <hr>
  
  <blockquote>
    <p>$ ./a.exe<br>
    Random COUT that makes this work<br>
    old_val!=new_val<br>
    0,40c3126f<br>
    diff_val = -6.096<br>
    Random COUT that makes this work<br>
    old_val==new_val<br>
    40c3126f,40c3126f<br>
    diff_val = 1.19209e-07  </p>
  </blockquote>
  
  <hr>
  
  <p>This is correct in that old_val == new_val, even though the subtraction still shows a slight difference.  </p>
  
  <p>This code also works under -O2 if feet is 2000, instead of 20000.  </p>
  
  <p>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 ==.  </p>
  
  <p>gcc version 3.4.4</p>