[comp.lang.c] Not A Number in IEEE Math

john@newave.UUCP (John A. Weeks III) (02/16/90)

My understanding of the NaN (not a number) value in IEEE math is
that once you get NaN, the operators +, -, /, *, and = are supposed
to propagate the NaN value.  Is my understanding correct?

Well, while using MetaWare's HIGH-C compiler for the 80386 chip, I
have discovered that:

			NaN / NaN = 1.0

			      and

			0.0 * NaN = 0.0.

Is this correct behavior?  I think HIGH-C is broken...

-john-

-- 
===============================================================================
John A. Weeks III               (612) 942-6969               john@newave.mn.org
NeWave Communications                ...uunet!rosevax!bungia!wd0gol!newave!john
===============================================================================

sarathy@gpu.utcs.utoronto.ca (Rajiv Sarathy) (02/20/90)

In article <44@newave.UUCP> john@newave.UUCP (John A. Weeks III) writes:
>
>My understanding of the NaN (not a number) value in IEEE math is
>that once you get NaN, the operators +, -, /, *, and = are supposed
>to propagate the NaN value.  Is my understanding correct?
>
>Well, while using MetaWare's HIGH-C compiler for the 80386 chip, I
>have discovered that:
>
>			NaN / NaN = 1.0
>
>			      and
>
>			0.0 * NaN = 0.0.
>
>Is this correct behavior?  I think HIGH-C is broken...

As long as only very, VERY, large numbers (positive or negative) are defined
to be NaNs (ie. not results of division by zero, and other silly things), then
the above behaviour makes sense.

	Mathematically:

		lim    __n__ = 1.0	and     lim   0.0 * n = 0.0
	       n->inf    n		       n->inf

	where inf is +/- infinity.

Unfortunately, NaNs encompass other floating-point exceptions as well, on some
machines.

-- 

 Rajiv Partha Sarathy  	      _  _ /^\    INTERNET sarathy@gpu.utcs.utoronto.ca
 ................ooooooooOOOO(_)(_)\_/      BITNET sarathy@utorgpu.bitnet
 University Of Toronto Computing Services     UUCP sarathy@utgpu.uucp

mac@ardent.com (02/20/90)

  In article <44@newave.UUCP> john@newave.UUCP (John A. Weeks III) writes:

>  Xref: ardent comp.lang.c:24861 comp.sys.ibm.pc.programmer:25
           ^ why ardent?
>  My understanding of the NaN (not a number) value in IEEE math is
>  that once you get NaN, the operators +, -, /, *, and = are supposed
>  to propagate the NaN value.  Is my understanding correct?
>  
>  Well, while using MetaWare's HIGH-C compiler for the 80386 chip, I
>  have discovered that:
>  
>  			NaN / NaN = 1.0
>  
>  			      and
>  
>  			0.0 * NaN = 0.0.
>  
>  Is this correct behavior?  I think HIGH-C is broken...
>  
>  -john-

	This behaviour is not correct.  Possibly the compiler has
folied you by presubstituting 1.0 for A/A and 0.0 for 0.0 * A at
compile time.
	
	Or, perhaps your hardware traps into the OS for IEEE exceptions
and the OS's handling of source exceptions is broken.

	Or, perhaps your hardware is not IEEE compliant....



--
Michael McNamara	(St)ardent, Inc.		mac@ardent.com

ok@goanna.oz.au (Richard O'keefe) (02/20/90)

In article <1990Feb19.172558.29696@gpu.utcs.utoronto.ca>,
sarathy@gpu.utcs.utoronto.ca (Rajiv Sarathy) writes:
> In article <44@newave.UUCP> john@newave.UUCP (John A. Weeks III) writes:
> >Well, while using MetaWare's HIGH-C compiler for the 80386 chip, I
> >have discovered that:
> >			NaN / NaN = 1.0
> >			0.0 * NaN = 0.0.
> >Is this correct behavior?  I think HIGH-C is broken...
> 
> As long as only very, VERY, large numbers (positive or negative) are defined
> to be NaNs (ie. not results of division by zero, and other silly things),
> then the above behaviour makes sense.
> Unfortunately, NaNs encompass other floating-point exceptions as well,
> on some machines.

Rajiv Sarathy is confused.  The IEEE 754 and IEEE 854 specify the
following kinds of values:
NUMBERS
    FINITE NUMBERS
	- minus zero (-0.0)
	- plus zero (+0.0)
	- denormalised numbers (numbers which are so small that the
		exponent field would underflow; the presence of these
		numbers means that an add or subtract of finite numbers
		cannot overflow
	- ordinary normalised numbers
    INFINITIES
	- minus infinity (1/(-0) = -infinity)
	- plus infinity (1/(+0) = +infinity)
NOT-A-NUMBERS
    SIGNALLING NaNs
	- strange-fella-number-you-touch-im-e-cry
    QUIET NaNs
	- propagate quietly

"very VERY large numbers" are mapped to plus or minus infinity.
The infinities are NOT NaNs.  Any machine which maps large numbers
to NaNs is _not_ IEEE conforming.  It is, however, the case that
	Infinity / Infinity = NaN
	Infinity * 0.0 = NaN

Note that (contra Rajiv Sarathy) it does *NOT* make sense for
Infinity/Infinity to yield 1.0, for then one would expect
(3*Infinity)/Infinity to be the same as 3*(Infinity/Infinity).
But the first would be 1.0 and the second 3.0.  A NaN or an exception
is all that makes sense here.

One requirement of the IEEE standards which is _very_ commonly ignored
is the requirement that the default behaviour for strange computations
is to return the appropriate Infinity (instead of signalling Overflow),
denormalised number (instead of signalling Underflow), or NaN (instead
of signalling Divide by zero or Invalid operand).

The IEEE standards are really quite short and not that hard to understand.
(What they are like to _implement_ is someone else's problem, thankfully.)

amull@Morgan.COM (Andrew P. Mullhaupt) (02/21/90)

In article <1990Feb19.172558.29696@gpu.utcs.utoronto.ca>, sarathy@gpu.utcs.utoronto.ca (Rajiv Sarathy) writes:
> As long as only very, VERY, large numbers (positive or negative) are defined
> to be NaNs (ie. not results of division by zero, and other silly things), then
> the above behaviour makes sense.
> 
> 	Mathematically:
> 
> 		lim    __n__ = 1.0	and     lim   0.0 * n = 0.0
> 	       n->inf    n		       n->inf
> 
> 	where inf is +/- infinity.

I would not be very convinced by this argument that (infinity/infinity)
should be taken to be 1.0, (similarly for the other). There are lots
of limits which are of the form (infinity / infinity) and they can have
any value you like. To wit:

                 n
      lim     -------  =  C 
     n->inf   csc C/n

covers all complex numbers C other than C=0, and a limit of that kind
is easy to find:

                 n
      lim      -----  =  0.
     n->inf       2
                 n

Needless to say, there are limits of the form (infinity/infinity) which
grow without bound, (these are sometimes said to have the value +infinity)
and just as well such limits can oscillate finitely or infinitely. Perhaps
the most reasonable thing to say about (infinity/infinity) without knowledge
of the limit it represents is that it is 'Not Necessarily a Number'.

Later,
Andrew Mullhaupt

amull@Morgan.COM (Andrew P. Mullhaupt) (02/21/90)

I forgot to mention that the limits in question in my previous posting
are required by IEEE to be NaN - that is 'Not a Number'.

Later,
Andrew Mullhaupt

simon@ms.uky.edu (G. Simon Gales) (02/21/90)

I think that that behavior is correct.  

	0.0 * (anything) = 0.0
and
	NaN / NaN = 1.0

Also a NaN/NaN situation is usually treated as 1, but this is definitely
not intended to be a -correct- result.  If you end up with NaNs in your
computation's results, you can't trust the answers you get.

-- 
Simon Gales@The University of Kentucky
   simon@ms.uky.edu             | 'Fate... protects fools, little children,
   simon@UKMA.BITNET            |  and ships named Enterprise.' 
   {rutgers, uunet}!ukma!simon  |                           - Riker, ST:TNG

ark@alice.UUCP (Andrew Koenig) (02/22/90)

In article <14266@s.ms.uky.edu>, simon@ms.uky.edu (G. Simon Gales) writes:

> I think that that behavior is correct.  

> 	0.0 * (anything) = 0.0
> and
> 	NaN / NaN = 1.0

Sorry, but that's not what IEEE says.

NaN is infinitely infectious.  That is: any operation that gives a
floating point result is supposed to return NaN if any of its operands
is NaN.  Relational operators all return `false' if either operand
is NaN.  Thus (x == x) is false if and only if x is NaN (unless,
of course, your implementation is broken).

Incidentally,

	0.0 * infinity = NaN (+ or - infinity -- I think it's implementation
		defined whether or not NaN has a sign)
	0.0 * NaN = NaN (as mentioned before)
	0.0 * anything else = 0.0

	NaN / NaN = NaN (as mentioned before)

	infinity / infinity = NaN
	infinity / NaN = Nan (as mentioned before)
	infinity / anything else = infinity
-- 
				--Andrew Koenig
				  ark@europa.att.com

foessmei@lan.informatik.tu-muenchen.dbp.de (Reinhard Foessmeier) (02/22/90)

In article <14266@s.ms.uky.edu> simon@ms.uky.edu (G. Simon Gales) writes:
>I think that that behavior is correct.  
>
>	0.0 * (anything) = 0.0
>and
>	NaN / NaN = 1.0

Mi tradukis la libron			I translated the book
		
		The 8087 primer (J. Palmer, S. Morse)

en la germanan, kaj ^gi diras en	into German, and it says in chapter 2:
^cap. 2:

Kiam la 8087 plenumas instrukcion	Whenever the 8087 executes an
uzantan NaN-on, la normala reago	instruction that accesses a NaN
estas redoni la NaN-on kiel		as an operand the normal reaction
rezulton; se ambaw operaciatoj		is to return that NaN as a result.
estas NaN-oj, la rezulto estas la	if both operands are NaNs, the
NaN-o kun la pli granda signifikanto.	result is the NaN with the greater
					significand.

					(Sorry, no verbatim quotation;
					I have only my translation at hand.)

^Car Palmer kaj Morse kvazaw		Since Palmer and Morse sort of
inventis la normon IEEE P754,		invented the IEEE P754 standard
tio ^sajnas fidinda priskribo		this seems a fairly reliable
de la normo.				description of the standard behavior.
>
>Also a NaN/NaN situation is usually treated as 1, but this is definitely
>not intended to be a -correct- result.  If you end up with NaNs in your
>computation's results, you can't trust the answers you get.
>

Devus esti inverse: Sen NaN-oj en	It should be the other way round:
la rezulto oni povas (iom) fidi...	With no NaNs in your result you
>-- 					should have (some) faith in it...

>Simon Gales@The University of Kentucky
>   simon@ms.uky.edu             | 'Fate... protects fools, little children,
>   simon@UKMA.BITNET            |  and ships named Enterprise.' 
>   {rutgers, uunet}!ukma!simon  |                           - Riker, ST:TNG

Reinhard Foessmeier, TU Muenchen
_____________________________
--
Reinhard F\"ossmeier, Technische Univ. M\"unchen | "Sendmail can safely be made
foessmeier@infovax.informatik.tu-muenchen.dbp.de | setuid to root" (E. Allman:
   [ { relay.cs.net | unido.uucp } ]             | SM Install&Operation Guide)

harish@ecebucolix.ncsu.edu (Harish P. Hiriyannaiah) (02/22/90)

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXX
# > As long as only very, VERY, large numbers (positive or negative) are
defined
# > to be NaNs (ie. not results of division by zero, and other silly
things), then
# > the above behaviour makes sense.
# > 
# > 
# > 		lim    __n__ = 1.0	and     lim   0.0 * n = 0.0
# > 	       n->inf    n		       n->inf
# > 
# > 	where inf is +/- infinity.


Sigh .....    I suppose you haven't had a basic course in limits of functions.
I thought any elementary course in Calculus will cover this topic.

The point is

inf/inf, 0/0, 0*inf, inf^0, 0^inf, inf-inf are all indeterminate. You have to
explicitly evaluate the limits in such cases. There are many ways of
doing this,
and one of  them is L' Hospital's rule.


harish pu. hi.				harish@ecebucolix.ncsu.edu

dougp@voodoo.ucsb.edu (02/22/90)

-Message-Text-Follows-
In article <10515@alice.UUCP>, ark@alice.UUCP (Andrew Koenig) writes...
>	0.0 * infinity = NaN (+ or - infinity -- I think it's implementation
>		defined whether or not NaN has a sign)
>	0.0 * NaN = NaN (as mentioned before)
>	0.0 * anything else = 0.0
> 
>	NaN / NaN = NaN (as mentioned before)
> 
>	infinity / infinity = NaN
>	infinity / NaN = Nan (as mentioned before)
>	infinity / anything else = infinity

Does this mean that compilers arn't alowed to optimize code?

Suppose someone writes:

double a,b;
a=NaN; /* who cares how*/
b=NaN;

a/a==1 /*can the compiler optomize this to TRUE ?*/
a/b!=1 /*this should work out to TRUE*/
0*a    /*can the compiler optomize this to 0? */

In most cases you never run into NaNs, I think I would prefer to
have the compiler optomize a/a to 1 and 0*a to zero.

harish@ecebucolix.ncsu.edu (Harish P. Hiriyannaiah) (02/23/90)

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

In article <4030@hub.UUCP>, dougp@voodoo.ucsb.edu writes:
> 
> In most cases you never run into NaNs, I think I would prefer to
> have the compiler optomize a/a to 1 and 0*a to zero.


	Such a compiler is "broken", since it is mathematically incorrect.


harish  pu. hi.					harish@ecebucolix.ncsu.edu

jsalter@slo.uucp (James Salter) (02/28/90)

In article <MAC.90Feb19133844@ben.ardent.com> mac@ardent.com (Michael McNamara) writes:
>
>  In article <44@newave.UUCP> john@newave.UUCP (John A. Weeks III) writes:
>
>>  My understanding of the NaN (not a number) value in IEEE math is
>>  that once you get NaN, the operators +, -, /, *, and = are supposed
>>  to propagate the NaN value.  Is my understanding correct?
>>  
>>  Well, while using MetaWare's HIGH-C compiler for the 80386 chip, I
>>  have discovered that:
>>  			NaN / NaN = 1.0
>>  			      and
>>  			0.0 * NaN = 0.0.
>>  Is this correct behavior?  I think HIGH-C is broken...
>>  -john-
>	This behaviour is not correct.  Possibly the compiler has
>folied you by presubstituting 1.0 for A/A and 0.0 for 0.0 * A at
>compile time.

Metaware hasn't been very good about identifying and correctly dealing
with NaNs.  They generate code which does not have the jp (jump if parity)
instruction around the compare of doubles.  Because of the flag bits
which get set in the 386, if the jp instruction is placed after the normal
conditional jump, even if one of the args is a NaN, it may *still* not
reach the jump if parity instruction.

If you check the assembler code, this should reveal itself.  To be fair,
Metaware isn't alone in this, lots of compilers don't do this right.

>	Or, perhaps your hardware traps into the OS for IEEE exceptions
>and the OS's handling of source exceptions is broken.

Probably not.

>	Or, perhaps your hardware is not IEEE compliant....

Well, sorta.  Depending on what 80386 level of hardware you have, you
may have some microcode problems.  But those should be getting fixed soon.
Contact your local Intel dealer about errata sheets.  Especially if you
have an 80387 chip in there, too.

>Michael McNamara	(St)ardent, Inc.		mac@ardent.com


jim/jsalter   IBM AWD   T465/(415)855-4427    VNET: JSALTER at PALOALTO
UUCP: ..!uunet!ibmsupt!jsalter               Disc: Any opinions are mine.
IP: ibmsupt!jsalter@uunet.uu.net                 "PS/2 it, or DIE!"

jsalter@slo.uucp (James Salter) (03/01/90)

In article <14266@s.ms.uky.edu> simon@ms.uky.edu (G. Simon Gales) writes:
>I think that that behavior is correct.  
>
[... 0.0 ...]
>	NaN / NaN = 1.0
>
>Also a NaN/NaN situation is usually treated as 1, but this is definitely
>not intended to be a -correct- result.  If you end up with NaNs in your
>computation's results, you can't trust the answers you get.

No.  It is *explicitly* stated in IEEE 854, Sec. 6.2, Paragraph 4 (or so)

	"Every operation involving one or two input NaNs, ..., if a
	floating-point result is to be delivered, shall deliver as its result
	a quiet NaN, which should be one of the input NaNs."

where "operation" above is defined (5.1):

	"An implementation shall provide the add, subtract, multiply, divide
	and remainder operations for any two operands ..."

Thus, NaN/NaN != 1.0; in fact, it *can* not be a representable floating
point number.  It is NaNQ (maybe with an exception thrown in if one of
the NaNs is signalling).

If you want a controversy, ask about pow(0.0,0.0), but NaN behavior is
specified quite completely.

>Simon Gales@The University of Kentucky

jim/jsalter   IBM AWD   T465/(415)855-4427    VNET: JSALTER at PALOALTO
UUCP: ..!uunet!ibmsupt!jsalter               Disc: Any opinions are mine.
IP: ibmsupt!jsalter@uunet.uu.net                 "PS/2 it, or DIE!"