12

I'm using -Ofast gcc option in my program cause latency requirements. I wrote simple test program:

#include <iostream>
#include <math.h>

static double quiet_NaN = std::numeric_limits<double>::quiet_NaN();

int main()
{
    double newValue = 130000; 
    double curValue = quiet_NaN; 
    printf("newValue = %f\n", newValue); 
    printf("curValue = %f\n", curValue); 
    printf("isnan(newValue) = %d\n", isnan(newValue)); 
    printf("isnan(curValue) = %d\n", isnan(curValue)); 
    printf("newValue == curValue %d\n", (newValue == curValue)); 
    printf("newValue != curValue %d\n", (newValue != curValue)); 
}

I've tried to run it with default flags and with -Ofast:

$ g++ TestPointer.cpp 
$./a.out 
newValue = 130000.000000
curValue = nan
isnan(newValue) = 0
isnan(curValue) = 1
newValue == curValue 0
newValue != curValue 1

$ g++ -Ofast TestPointer.cpp 
$ ./a.out 
newValue = 130000.000000
curValue = nan
isnan(newValue) = 0
isnan(curValue) = 1
newValue == curValue 1
newValue != curValue 0

So the result of != and == can not be trusted. Does it mean that I should == and != only when both values are known to be not nan, otherwise I should test with isnan before?

Is it guaranteed that isnan works correctly with -Ofast? How correctly == and != works for double with -Ofast? Can someone provide complete list of limitations added by -Ofast?

einpoklum
  • 118,144
  • 57
  • 340
  • 684
Oleg Vazhnev
  • 23,239
  • 54
  • 171
  • 305
  • Why are you using -Ofast in the first place? Did you read the doc? It is the same as -O3 -ffast-math, where -ffast-math means you don't care if float/double give wrong results as long as they are fast... – Marc Glisse Dec 06 '14 at 09:02

1 Answers1

14

You're observing the effects of -ffast-math.

From the docs:

-Ofast

Disregard strict standards compliance. -Ofast enables all -O3 optimizations. It also enables optimizations that are not valid for all standard-compliant programs. It turns on -ffast-math and the Fortran-specific -fno-protect-parens and -fstack-arrays.

and

-ffast-math

Sets -fno-math-errno, -funsafe-math-optimizations, -fno-trapping-math, -ffinite-math-only, -fno-rounding-math, -fno-signaling-nans and fcx-limited-range.

and

-ffinite-math-only

Allow optimizations for floating-point arithmetic that assume that arguments and results are not NaNs or +-Infs.

There are several gcc bug reports for this marked invalid.

Problems with -ffast-math and isnan

Additionally, comparison of strict IEEE floating points always results in false.

Checking if a double (or float) is NaN in C++

This doesn't necessarily apply for -ffast-math but it explains what you show.

gcc does not describe a formal standard for how -ffast-math floats work so you'll just have to work out the details empirically if you must and not assume consistency between versions of gcc. Better yet, completely avoid the combination of NaN and -ffast-math.

Community
  • 1
  • 1
Praxeolitic
  • 22,455
  • 16
  • 75
  • 126
  • can I use `isnan` and `-Ofast`? will it work? Or it is not guaranteed and sometimes I can get true, sometimes false? – Oleg Vazhnev Dec 05 '14 at 12:50
  • You should avoid the combination of NaN and `-ffast-math` completely but my guess is that `isnan` will behave as expected for an explicitly set NaN. Even if it does though, don't assume it always will. – Praxeolitic Dec 05 '14 at 13:20
  • do you know how can I set `-Ofast` except `-ffast-math`? – Oleg Vazhnev Dec 05 '14 at 13:53
  • 1
    Check the description of `-Ofast` above. Without `-ffast-math` it's just O3. – Praxeolitic Dec 05 '14 at 13:57
  • 1
    are you sure? Why someone need `-Ofast` then? Why just not using `-O3` and `-ffast-math`? What is the reason to introduce special option to combine just two options? – Oleg Vazhnev Dec 06 '14 at 11:02
  • The docs are quite clear on what `-Ofast` does. If you're compiling Fortran it does do more than `-ffast-math`. I guess it's there to have an O level means "do everything, even if it isn't quite standards compliant" and at the moment that only includes `-ffast-math` for C++. – Praxeolitic Dec 06 '14 at 15:35
  • 1
    I should mention that (at least in GCC 6+), I observe strange behavior with regards to aliasing with -Ofast that does not occur with -O3 -ffast-math in C. Although this doesn't apply to math per se, it reveals there are more differences than the docs claim. – user1649948 Sep 02 '17 at 19:13