Richard Miller
2013-08-21 13:17:25 UTC
The Plan 9 C compilers do not appear to be compliant with the IEEE floating
point standard when making comparisons with NaN (not a number) values.
The standard says a comparison with one or both operands NaN is "unordered",
ie all relations evaluate to false, except != which is always true.
Testing with this fragment of code:
double a, b;
setfcr(0);
a = 0.0;
b = sqrt(-1.0);
if(a < b) print(" (a < b)");
if(a <= b) print(" (a <= b)");
if(a == b) print(" (a == b)");
if(a != b) print(" (a != b)");
if(a >= b) print(" (a >= b)");
if(a > b) print(" (a > b)");
if(b < a) print(" (b < a)");
if(b <= a) print(" (b <= a)");
if(b == a) print(" (b == a)");
if(b != a) print(" (b != a)");
if(b >= a) print(" (b >= a)");
if(b > a) print(" (b > a)");
print("\n");
on ARM the result is almost completely wrong:
(a < b) (a <= b) (a != b) (b < a) (b <= a) (b != a)
and on x86 the result is even wronger:
(a < b) (a <= b) (a == b) (b < a) (b <= a) (b == a)
compared to the IEEE expected result, for example on MacOS:
(a != b) (b != a)
This was discovered by fgb; I've been looking into the cause -- which is
mainly the assumption, in the compiler and linker, that something like this:
if (a < b) f();
can safely be transformed to this:
if (a >= b) goto skip;
f();
skip:
Unfortunately if a or b is NaN, the conditional will be false in both cases.
So is this a feature, or a bug that needs fixing?
point standard when making comparisons with NaN (not a number) values.
The standard says a comparison with one or both operands NaN is "unordered",
ie all relations evaluate to false, except != which is always true.
Testing with this fragment of code:
double a, b;
setfcr(0);
a = 0.0;
b = sqrt(-1.0);
if(a < b) print(" (a < b)");
if(a <= b) print(" (a <= b)");
if(a == b) print(" (a == b)");
if(a != b) print(" (a != b)");
if(a >= b) print(" (a >= b)");
if(a > b) print(" (a > b)");
if(b < a) print(" (b < a)");
if(b <= a) print(" (b <= a)");
if(b == a) print(" (b == a)");
if(b != a) print(" (b != a)");
if(b >= a) print(" (b >= a)");
if(b > a) print(" (b > a)");
print("\n");
on ARM the result is almost completely wrong:
(a < b) (a <= b) (a != b) (b < a) (b <= a) (b != a)
and on x86 the result is even wronger:
(a < b) (a <= b) (a == b) (b < a) (b <= a) (b == a)
compared to the IEEE expected result, for example on MacOS:
(a != b) (b != a)
This was discovered by fgb; I've been looking into the cause -- which is
mainly the assumption, in the compiler and linker, that something like this:
if (a < b) f();
can safely be transformed to this:
if (a >= b) goto skip;
f();
skip:
Unfortunately if a or b is NaN, the conditional will be false in both cases.
So is this a feature, or a bug that needs fixing?