[comp.lang.c] NaN's

gwc@root.co.uk (Geoff Clare) (05/31/91)

henry@zoo.toronto.edu (Henry Spencer) writes:

>  If you are willing to constrain your code to run on machines using
>IEEE floating point, you could use a NaN value... but there is no standard
>way of generating such a value or testing for it.

I agree there is no standard way of generating NaN (although sqrt(-1.0)
is your best bet).  However, there is a standard way of testing for NaN.
If x is a floating point variable, then (x != x) will be TRUE if and
only if x has the value NaN.
-- 
Geoff Clare <gwc@root.co.uk>  (Dumb American mailers: ...!uunet!root.co.uk!gwc)
UniSoft Limited, London, England.   Tel: +44 71 729 3773   Fax: +44 71 729 3273

sarima@tdatirv.UUCP (Stanley Friesen) (06/01/91)

In article <2726@root44.co.uk> gwc@root.co.uk (Geoff Clare) writes:
>I agree there is no standard way of generating NaN (although sqrt(-1.0)
>is your best bet).  However, there is a standard way of testing for NaN.
>If x is a floating point variable, then (x != x) will be TRUE if and
>only if x has the value NaN.

But what if the compiler notices you are asking for a self comparison and
optimizes it away?  Then this will fail unless x is volatile.

Since NaN's fall in the area of unspecified/undefined behavior I believe
that such an optimization is legal under the ANSI standard.
-- 
---------------
uunet!tdatirv!sarima				(Stanley Friesen)

steve@taumet.com (Stephen Clamage) (06/02/91)

sarima@tdatirv.UUCP (Stanley Friesen) writes:

>In article <2726@root44.co.uk> gwc@root.co.uk (Geoff Clare) writes:
>>I agree there is no standard way of generating NaN (although sqrt(-1.0)
>>is your best bet).  However, there is a standard way of testing for NaN.
>>If x is a floating point variable, then (x != x) will be TRUE if and
>>only if x has the value NaN.

>But what if the compiler notices you are asking for a self comparison and
>optimizes it away?  Then this will fail unless x is volatile.

>Since NaN's fall in the area of unspecified/undefined behavior I believe
>that such an optimization is legal under the ANSI standard.

The IEEE standard for floating-point recommends a set of functions to
be made available.  Among these are functions to classify a value
as NaN, Infinity, Zero, Denormalized, Normalized, and so on.  Most
implementations I am familiar with provide this functionality,
although there are no standard names for the functions.  Such
implementations often provide predefined identifiers (such as _NaN,
_Infinity, etc) to allow you to generate these values.  There is a
group working on proposing standard extensions to C for numerical
work.  Perhaps they will recommend standards in this area.

In the mean time, you can write your own "standard" functions and macros,
and provide versions of them for each system you use.  If the system
provides the functions you need, you #define your "standard" functions
to be the system functions.  Otherwise, you write your function as an
interface to what the system provides, or write your own from scratch.
This is all rather easy to do, but is system-specific.

Some of the suggestions in this thread for portable ways to generate or
test for a NaN are not all that portable.  For example, sqrt(-1.0) might
generate a trap, and in any case might not return a NaN.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

henry@zoo.toronto.edu (Henry Spencer) (06/02/91)

In article <14@tdatirv.UUCP> sarima@tdatirv.UUCP (Stanley Friesen) writes:
>>... there is a standard way of testing for NaN.
>>If x is a floating point variable, then (x != x) ...
>
>But what if the compiler notices you are asking for a self comparison and
>optimizes it away?  Then this will fail unless x is volatile.
>Since NaN's fall in the area of unspecified/undefined behavior I believe
>that such an optimization is legal under the ANSI standard.

But not under the IEEE FP standard.  Compilers need to be *very* careful
about optimizing floating-point operations if they are to provide a fully
IEEE-conforming environment.  A good many seemingly-innocuous operations
run into trouble.  It is simply a fact that in IEEE floating point, x!=x
is sometimes true, and optimizing it to `false' is a compiler bug.
-- 
"We're thinking about upgrading from    | Henry Spencer @ U of Toronto Zoology
SunOS 4.1.1 to SunOS 3.5."              |  henry@zoo.toronto.edu  utzoo!henry

jlg@cochiti.lanl.gov (Jim Giles) (06/02/91)

In article <1991Jun1.214347.11696@zoo.toronto.edu>, henry@zoo.toronto.edu (Henry Spencer) writes:
|> [...]           It is simply a fact that in IEEE floating point, x!=x
|> is sometimes true, and optimizing it to `false' is a compiler bug.

I depends on how the `!=' operator is defined in C.  The only relational
predicate that evaluates `true' under IEEE FP is `unordered'.  So, if 
`!=' is defined as `?<>' (in the IEEE notation: `?' stands for `unordered?'), 
then it will evaluate `x!=x' as `true' if x is a NAN.  However, if `!=' is
defined as `<>', then it will _always_ evaluate `x!=x' as `false'. 

I can't find any specific reference in the ANSI C document which defines
which behaviour is appropriate.  The ANSI/IEEE document Std 754-1985 
(IEEE Standard for Binary Floating-Point Numbers) _recommends_ that the
_Fortran_ operator .NE. should be defined as `?<>'.  Neither the Fortran
nor the C ANSI documents (proposals, in the case of Fortran) mention
the issue at all.

J. Giles

henry@zoo.toronto.edu (Henry Spencer) (06/02/91)

In article <24890@lanl.gov> jlg@cochiti.lanl.gov (Jim Giles) writes:
>|> [...]           It is simply a fact that in IEEE floating point, x!=x
>|> is sometimes true, and optimizing it to `false' is a compiler bug.
>
>I depends on how the `!=' operator is defined in C...

Hmm, good point.

>I can't find any specific reference in the ANSI C document which defines
>which behaviour is appropriate.  The ANSI/IEEE document Std 754-1985 
>(IEEE Standard for Binary Floating-Point Numbers) _recommends_ that the
>_Fortran_ operator .NE. should be defined as `?<>'...

ANSI C doesn't touch the issue because C exists on many non-IEEE platforms
and there didn't seem to be much prior art on which to base even an optional
specification for an IEEEFP interface.  (X3J11, unlike a lot of other
standards committees, usually took "standardize existing practice, don't
try to invent it" pretty seriously.)  However, in the absence of anything
more precise, I think we could take 754's advice on FORTRAN as relevant
to C as well.

The NCEG is attempting to come up with a consensus C->754 interface,
I believe.
-- 
"We're thinking about upgrading from    | Henry Spencer @ U of Toronto Zoology
SunOS 4.1.1 to SunOS 3.5."              |  henry@zoo.toronto.edu  utzoo!henry

bright@nazgul.UUCP (Walter Bright) (06/04/91)

In article <14@tdatirv.UUCP> sarima@tdatirv.UUCP (Stanley Friesen) writes:
/>In article <2726@root44.co.uk> gwc@root.co.uk (Geoff Clare) writes:
/>I agree there is no standard way of generating NaN (although sqrt(-1.0)
/>is your best bet).  However, there is a standard way of testing for NaN.
/>If x is a floating point variable, then (x != x) will be TRUE if and
/>only if x has the value NaN.
/But what if the compiler notices you are asking for a self comparison and
/optimizes it away?  Then this will fail unless x is volatile.

If the compiler supports NaNs, it will not do such optimizations. Note that
there is a proposed standard for generating NaNs, it is put out by the
NCEG (Numerical C Extensions Group). The idea is that there is a NAN macro,
which generates a quiet NaN, and a NANS macro, which generates a signalling
NaN. Both can be used for static initialization of floating point variables.
(Which is impractical if you are using sqrt(-1) to generate a NaN.)

Many C implementations claim to be IEEE 748 conformant, but if you try
the (x!=x) test above with x being a NaN, you'll find that they aren't
very conformant. (x!=x) not only is supposed to return TRUE, but also does
not raise the invalid exception when x is a NaN. This is where most
implementations fall down, including some Fortrans!

Zortech C/C++ 3.0 is the first implementation of NCEG and IEEE 748 for C
that I'm aware of. It includes full support for programming with NaNs.
It also includes all 26 IEEE 748 comparison operators!

If you'd like more information, please email me a note and I'll email you
a brochure.