Reputation: 2648
Consider the following test program:
# include <gsl/gsl_statistics_double.h>
# include <iostream>
using namespace std;
int main()
{
double y = 50.2944, yc = 63.2128;
double pearson_corr = gsl_stats_correlation(&y, 1, &yc, 1, 1);
cout << "pearson_corr = " << pearson_corr << endl;
if (isnan(pearson_corr))
cout << "It is nan" << endl;
else
cout << "Not nan" << endl;
}
In some way, this code is some absurd, but its purpose is to show a subtle error that I am experiencing.
The call to gsl_stats_correlation()
should give an error because the number of samples is 1 and the pearson coefficient has sense for at least two samples.
When I compile thus:
c++ test-r2.cc -lgsl -lgslcblas
the programs prints out -nan
as result and the message "It is nan", which I consider correct because as I said it is not possible to compute the coefficient. The call to isnan()
detects correctly that the result is nan
. However, when I compile thus:
c++ -Ofast test-r2.cc -lgsl -lgslcblas
The program prints out -nan
as result but the message "Not nan", which suggests that the call to isnan()
was unable to detect the invalidity of pearson_corr
variable.
So, my first question es "Why with the -Ofast
flag the call to isnan()
is not able to detect that the variable is nan
. And my second question would be how to solve this problem in a way independent on the optimizations flags given to the compiler?
I am using gnu c++ version 5.4.0 on ubuntu 16.04 and an Intel i5 run at 64 bits mode
Thanks in advance
Upvotes: 3
Views: 2694
Reputation: 29970
You can use this option: -Ofast -fno-finite-math-only
, so isnan
still works.
Or, if you don't want to use -fno-finithe-math-only
, but still want to detect NaN numbers, you can do it in a platform dependent way: implement your own isnan
function.
For example, if you're on a IEEE-754 platform with floats 32-bit and doubles 64-bit, you can do:
#include <cstdint>
#include <string.h>
bool myIsnan(float v) {
std::uint32_t i;
memcpy(&i, &v, 4);
return ((i&0x7f800000)==0x7f800000)&&(i&0x7fffff);
}
bool myIsnan(double v) {
std::uint64_t i;
memcpy(&i, &v, 8);
return ((i&0x7ff0000000000000)==0x7ff0000000000000)&&(i&0xfffffffffffff);
}
Upvotes: 2
Reputation: 140276
-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 in that case isnan
doesn't work, as explained better here Mingw32 std::isnan with -ffast-math
(one of the answers contains an implementation which will work, but it's also possible to wrap isnan
in a c file which isn't compiled with -Ofast
)
Upvotes: 3
Reputation: 281683
You told GCC to assume no NaNs, so it's assuming no NaNs. Any code that depends on NaNs is obviously not going to be reliable if you do that.
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 -fstack-arrays, unless -fmax-stack-var-size is specified, and -fno-protect-parens.
-ffast-math
Sets the options -fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only, -fno-rounding-math, -fno-signaling-nans, -fcx-limited-range and -fexcess-precision=fast. ...
-ffinite-math-only
Allow optimizations for floating-point arithmetic that assume that arguments and results are not NaNs or +-Infs.
Upvotes: 1
Reputation: 140786
-Ofast
, among other things, activates GCC's -ffast-math
mode, and -ffast-math
, among other things, causes the compiler to generate code that assumes that NaN (and Inf) never occur.
Therefore, if you need to use NaN or Inf, you must not use -Ofast
. There is no workaround.
Nearly all programs are better served by -O2 -march=native
anyway; -Ofast
turns on extremely aggressive inlining and loop unrolling that, in my experience, almost always blow the I-cache and make the program slower.
Upvotes: 13
Reputation: 14947
man gcc
says this:
-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 this:
-ffast-math
Sets -fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only, -fno-rounding-math, -fno-signaling-nans and -fcx-limited-range.
This option causes the preprocessor macro "__FAST_MATH__" to be defined.
This option is not turned on by any -O option besides -Ofast since it can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications
for math functions. It may, however, yield faster code for programs that do not require the guarantees of these specifications.
You are telling the compiler to ignore NaNs, among other strange species of a the floating-point family. If you don't want the compiler to do that, tell it -O2
or -O3
instead.
Upvotes: 4