Bug 45691 - Floating point comparison failure
Summary: Floating point comparison failure
Status: RESOLVED DUPLICATE of bug 323
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 4.5.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-09-16 16:57 UTC by Ian Macky
Modified: 2010-09-16 17:15 UTC (History)
70 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ian Macky 2010-09-16 16:57:58 UTC
After upgrading to gcc 4.5.0 from 3.3.4, some of my floating point code fails.  Searched for and could not find a matching bug.  It boils down to this very simple example:

#include <stdio.h>

#define MY_PI   3.14159265358979323846

int main()
{
    double z = MY_PI;
    puts(z == MY_PI ? "==" : "!=");
    return 0;
}

If this is compiled "gcc -o bug -Wall bug.c" it works: there is equality.  Doesn't matter if optimization is used or not (-g, -O, -O2 all give same results).

But if compiled with -ansi or -std=c99, then the equality fails, again regardless of optimization!!

The preprocessed code looks as expected:

int main()
{
    double z = 3.14159265358979323846;
    puts(z == 3.14159265358979323846 ? "==" : "!=");
    return 0;
}

Cannot see how this is correct behavior since the exact same expression was used to initialize the variable and to test for equality.  Do not see anything in my ANSI/ISO C reference that sheds any light.

I can work around this by using actual double constants instead of preprocessor expressions ("double my_pi_2 = MY_PI_2" and setting/testing with my_pi_2, etc), but this should work as is!
Comment 1 Dominique d'Humieres 2010-09-16 17:02:55 UTC
pr323?

As a general rule: never compare floating points for equality, use abs(a-b)<epsilon.
Comment 2 Paolo Carlini 2010-09-16 17:08:08 UTC
As an even more general rule, remember to always specify your target: in this case, for example, I can't reproduce at all the behavior on x86_64 -m64, only with -m32.
Comment 3 Andrew Pinski 2010-09-16 17:08:40 UTC

*** This bug has been marked as a duplicate of 323 ***

*** This bug has been marked as a duplicate of 323 ***
Comment 4 Jakub Jelinek 2010-09-16 17:13:04 UTC
i?86 is a FLT_EVAL_METHOD 2 target, so for strict C compliance all floating
operations and constants are supposed to be evaluated in the precision
of long double.  The assignment of the constant to a double var or explicit
cast to double cause rounding to happen, so your testcase is evaluated as:
  int main()
  {
      double z = 3.14159265358979323846L;
      puts((long double) z == 3.14159265358979323846L ? "==" : "!=");
      return 0;
  }
and of course (double) 3.14159265358979323846L != 3.14159265358979323846L.
You can use -fexcess-precision=fast (the default unless -std=c99/-std=c89
is requested) for the old behavior, or you can add explicit cast,
z == (double) M_PI, or (as usually a good idea) avoid floating point
equality/non-equality comparisons, instead check whether difference is
smaller than some epsilon. 
Comment 5 Paolo Carlini 2010-09-16 17:15:58 UTC
Thanks Jakub.
Comment 6 Ian Macky 2010-09-16 17:44:03 UTC
Subject: Re:  Floating point comparison failure

Thanks everyone.  I usually do fuzzy floating-point comparison, except in
certain special circumstances.  I will switch to using double constants;
I'm trying for a code that is maximally portable, so having to worry about
what exact compiler switches to use is anathema.

And might I add: you people are super-fast!  I'm very impressed.