IEEE floating-point and negative zero.
uunet!netcom.com!segfault!rfg
uunet!netcom.com!segfault!rfg
Sat Mar 27 14:08:40 PST 1993
Some time ago, I mentioned on this mailing list that it would be really
nice to have a formal, official, and "standard" binding of ANSI/ISO C
to the IEEE 754 and/or 854 floating-point standards. (Note that such
a "binding" could be entirely independent of the floating-point *extensions*
which NCEG has proposed.)
Anyway, we don't have such a thing at the moment, and it doesn't appear
that anyone is working on even developing a draft of such a thing at this
time. :-(
In the absence of such a "standard binding", we have to struggle along as
best we can, using whatever reasonable guidelines seem to be available.
Well, the only set of "reasonable guidelines" that I have found so far
is the NCEG's "Floating-point C Extensions" document. Although the
primary aim of this document is to specify several "extensions" (over
and above ANSI/ISO C) it also contains a lot of material which (in effect)
specifies "reasonable" rules for binding the existing ANSI/ISO C standard
to the IEEE floating-point standards.
Recently, I have used some of this material as a basis for writing a few
test cases for C compilers. These test cases attempt to check that C
compilers (whose targets claim to support IEEE floating-point) do in fact
implement a "reasonable" binding of C to the IEEE floating-point standards.
Some of these tests have been based upon the restrictions described in
appendix B.2 of the NCEG's "Floating-point C Extensions" document for
IEEE conformant targets. In particular, I have just written a simple
test which checks one aspect of the third restriction given in B.2.
The first part of this restriction reads roughly as follows:
"(x-y) is not equivalent to -(y-x). For IEEE machines, in the
default rounding direction, (1-1) is +0 but -(1-1) is -0..."
I developed a C langauge test of this restriction, and it is provided below.
(Note that I have copyrighted it, and I retain copyright, but I grant people
on this list permission to save and use the test as long as the copyright
message is retained.)
The test is written in such a way that a C compiler only "passes" the test
if it produces an executable from this code which exits quietly with a zero
exit status. If the test "fails" in any way, you will know about it because
the executable (when run) will write one or more "failure" messages to stdout,
and will exit with a non-zero status.
Anyway, the thing that bothers me (and the reason I have written this message)
is that I have yet to find *any* C compiler which fully "passes" this simple
test even though I have tried eleven different C compilers on six different
architectures.
The test is simple enough. It tries (in various way) to create a negative
zero, and then checks to see that the kind of zero produced does in fact
have a negative sign. (It seems that the *only* portable way to inspect
the sign of a floating-point zero is to exploit the IEEE rule which says
that dividing by zero produces an infinity with the appropriate sign.)
Most compilers *do* produce a negative zero in cases where the expressions
involved are obviously not compile-time constant expressions, although some
compilers with overly-agressive optimizers fail to produce code which yields
negative zero for expression like -(one-one) where `one' is a variable.
One compiler (for a recent entry into the RISC wars) produced code which
simply crashed at run-time (probably as a result of mishandling of divisions
by zero).
All compilers tested failed to produce negative zero for expressions like
-(0) and -(1-1) regardless of whether or not the -O (optimization) option
was used.
So my question is a simple one. Are all these compilers failing to implement
a "reasonable" binding of ANSI/ISO C to the IEEE floating-point standards,
or is there something obvious that I'm missing?
P.S. On a separate (but related) topic, if there ever *is* a "standard
binding" of C to IEEE floating-point, it would be really nice if it specified
how such things as -0, Infinities, qNaNs, and sNaNs would be treated by the
members of the *printf family of standard library functions.
// rfg
cut here... test case code follows
=============================================================================
/* (C) 1993 Ronald F. Guilmette; all rights reserved. */
/* Check that the signedness of zero is respected.
This test is appropriate only for target systems claiming to support
the IEEE 754 or 854 floating-point standards.
*/
#include <stdio.h>
int err_count = 0;
double zero = 0.0;
double one = 1.0;
double some_infinity;
double d;
int
test ()
{
d = -(0);
some_infinity = 1.0/d;
if (some_infinity > 0) /* CHECK */
{
printf ("negating (0) doesn't produce -0\n");
err_count++;
}
d = -(zero);
some_infinity = 1.0/d;
if (some_infinity > 0) /* CHECK */
{
printf ("negating (zero) doesn't produce -0\n");
err_count++;
}
d = -(1-1);
some_infinity = 1.0/d;
if (some_infinity > 0) /* CHECK */
{
printf ("negating (1-1) doesn't produce -0\n");
err_count++;
}
d = -(one-one);
some_infinity = 1.0/d;
if (some_infinity > 0) /* CHECK */
{
printf ("negating (one-one) doesn't produce -0\n");
err_count++;
}
return err_count;
}
int main () { return test (); }
More information about the Numeric-interest
mailing list