double-precision NaN less-than FiniteValue returns TRUE with gcc -O, -O2, and higher on X86_64

I see a problem with ACML if it is being built with GCC 3.4. The following demonstrates how NaN is mistreated when optimization, even -O let alone -O2, is enabled. In the following, when optimization is not enabled, the output is correctly "nan" since IEEE standards dictate that (x > max) must return FALSE when x=NAN and (x < min) must return FALSE when x=NAN. Therefore, f(x) must return x when x=NAN. This does not happen, for some reason the (x < min) branch is taken and -1 is returned. Will ACML be built with GCC 4.x? I'm not sure how I can trust double-precision arithmetic otherwise.

gcc-3.4 Output without optimization: "nan" (correct)

gcc-3.4 Output with optimization: "-1" (wrong)

gcc-4.x Output always: "nan" (correct)

Source:

#include <iostream>

#include <stdint.h>

#include <math.h>

double f(double x)

{

static const double max = 1;

static const double min = -1;

if(x > max) {

return max;

} else if(x < min) {

return min;

} else {

return x;

}

}

int main(int argc, char** argv)

{

double x = 0;

double y = 0;

x /= y;

std::cerr << f(x) << std::endl;

return 0;

}

I see a problem with ACML if it is being built with GCC 3.4. The following demonstrates how NaN is mistreated when optimization, even -O let alone -O2, is enabled. In the following, when optimization is not enabled, the output is correctly "nan" since IEEE standards dictate that (x > max) must return FALSE when x=NAN and (x < min) must return FALSE when x=NAN. Therefore, f(x) must return x when x=NAN. This does not happen, for some reason the (x < min) branch is taken and -1 is returned. Will ACML be built with GCC 4.x? I'm not sure how I can trust double-precision arithmetic otherwise.

gcc-3.4 Output without optimization: "nan" (correct)

gcc-3.4 Output with optimization: "-1" (wrong)

gcc-4.x Output always: "nan" (correct)

Source:

#include <iostream>

#include <stdint.h>

#include <math.h>

double f(double x)

{

static const double max = 1;

static const double min = -1;

if(x > max) {

return max;

} else if(x < min) {

return min;

} else {

return x;

}

}

int main(int argc, char** argv)

{

double x = 0;

double y = 0;

x /= y;

std::cerr << f(x) << std::endl;

return 0;

}

We currently build with GCC 4.1.2 and GCC 4.2.0 (for the OpenMP version), so this issue should not be a problem.

of what the IEEE 754 arithmetic standard says. That standard (section 5.7) says that NaNs compare as "unordered" with all other numbers,

including other NaNs. The standard also recommends using a function isnan() to detect whether a value is a NaN. In my experience,

a Fortran comparison involving a NaN can go any which way, and the same comparison written in two parts of the same routine

might go two different ways.

Even if the high level language handled NaNs in the way you would like, I'm not sure it would help much.

LAPACK, BLAS and other routines are not generally designed to expect NaNs. So, however NaN's are handled,

the results you get from a routine call might not be what you expect if you supply input data (e.g. a matrix element) containing a NaN.

You might or might not get a NaN returned in your results.