[R6RS] NaNs and infinities

William D Clinger will at ccs.neu.edu
Sat Mar 4 15:52:49 EST 2006

```Mike is revising the arithmetic SRFI, and some questions
about infinities and NaNs have come up.  I'd like to
bring these subtleties to the attention of the editors,
and get these details into the R6RS archives.

> OK, but (nan? (sqrt -1.0)) => #t, right?

Not necessarily.  We aren't requiring implementations to
support NaNs in any way, because they are pretty specific
to IEEE-754.  In particular, the external representation
nan.0 might just be a name for 17.0, +nan.0 might be a
name for -46.3, and -nan.0 might be a name for 3.14159.

Similarly, +inf.0 and -inf.0 might be names for the
largest and smallest representable inexact reals.

I just went through SRFI 77, checking every occurrence
of nan and inf.  Here is what the current (unpublished)
working draft of SRFI 77 actually requires, with my

+inf.0 represents the result of (/ 1.0 0.0).
-inf.0 represents the result of (/ -1.0 0.0).
+nan.0 represents the result of (/ 0.0 0.0).

inf.0, +inf.0, -inf.0, nan.0, +nan.0, and -nan.0 are
external representations for flonums.

(real? +nan.0)  ==>  #t
(rational? +nan.0)  ==>  #f        ; should be unspecified
(number? +nan.0)  ==>  #t
(complex? +nan.0)  ==>  #t
(rational? +nan.0)  ==>  #f        ; this incorrect example appears twice
(real-valued? +nan.0)  ==>  #t
(rational-valued? +nan.0)  ==>  #f ; should be unspecified
(string->number "+nan.0")  ==>  +nan.0
(fl= +nan.0 fl)  ==>  unspecified
(fl= +nan.0 fl)  ==>  unspecified  ; this example appears twice
(fl< +nan.0 fl)  ==>  unspecified
(fl/ 0.0 0.0)  ==>  +nan.0

In safe mode, flfloor, flceiling, fltruncate, and flround
signal an error when passed an infinity or NaN.  In unsafe
mode, all bets are off.  In both safe and unsafe mode,
these procedures signal an error if no integral flonum
satisfying the above conditions exists.  [Note: this is
not a good idea IMO, and is inconsistent with the examples
in any case.]

(fllog -inf.0)  ==>  +nan.0

The inexact-floor, inexact-ceiling, inexact-truncate, and
inexact-round procedures signal an error when passed an
infinity or NaN, or when no integral number satisfying
the above conditions exists.

(+ +inf.0 -inf.0)  ==>  +nan.0
(+ +nan.0 x)  ==>  +nan.0          ; should be unspecified
(* +nan.0 x)  ==>  +nan.0          ; should be unspecified
(- +inf.0 +inf.0)  ==>  +nan.0
(/ 0 0.0)  ==>  unspecified
(/ 0.0 0)  ==>  +nan.0
(/ 0.0 0.0)  ==>  +nan.0
(rationalize +inf.0 +inf.0)  ==>  +nan.0
(real? -inf.0)  ==>  #t
(rational? -inf.0)  ==>  #f        ; should be unspecified
(complex? +inf.0)  ==>  #t
(integer? -inf.0)  ==>  #f
(real-valued? -inf.0)  ==>  #t
(rational-valued? -inf.0)  ==>  #f ; should be unspecified
(inexact? +inf.0)  ==>  #t
(string->number "+inf.0")  ==>  +inf.0
(string->number "-inf.0")  ==>  -inf.0
(fl= +inf.0 +inf.0)  ==>  #t
(fl= -inf.0 +inf.0)  ==>  #f
(fl= -inf.0 -inf.0)  ==>  #t
(fl/ 1.0 0.0)  ==>  +inf.0
(fl/ -1.0 0.0)  ==>  -inf.0
(flnumerator +inf.0)  ==>  +inf.0
(flnumerator -inf.0)  ==>  -inf.0
(fldenominator +inf.0)  ==>  1.0    ; should be unspecified
(fldenominator -inf.0)  ==>  1.0    ; should be unspecified
(flfloor +inf.0)  ==>  +inf.0       ; should be unspecified or "is an error"
(flceiling -inf.0)  ==>  -inf.0     ; should be unspecified or "is an error"
(flexp +inf.0)  ==>  +inf.0
(flexp -inf.0)  ==>  0.0
(fllog +inf.0)  ==>  +inf.0         ; should be unspecified
(fllog 0.0)  ==>  -inf.0
(fllog -inf.0)  ==>  +nan.0
(flatan -inf.0)  ==>  -1.5707963267948965   ; depends on precision etc
(flatan +inf.0)  ==>  1.5707963267948965    ; depends on precision etc
(flsqrt +inf.0)  ==>  +inf.0                ; should be unspecified
(flonum->fixnum -inf.0)  ==>  -8388608      ; correct under supposition
(= +inf.0 +inf.0)  ==>  #t
(= -inf.0 +inf.0)  ==>  #f
(= -inf.0 -inf.0)  ==>  #t
(< -inf.0 x +inf.0)  ==>  #t        ; provided x is neither infinite nor NaN
(> +inf.0 x -inf.0)  ==>  #t        ; provided x is neither infinite nor NaN
(positive? +inf.0)  ==>  #t
(negative? -inf.0)  ==>  #t
(max +inf.0 x)  ==>  +inf.0
(min -inf.0 x)  ==>  -inf.0
(+ +inf.0 +inf.0)  ==>  +inf.0
(+ +inf.0 -inf.0)  ==>  +nan.0      ; should be unspecified
(+ 5 +inf.0)  ==>  +inf.0
(* -5 +inf.0)  ==>  -inf.0
(* +inf.0 +inf.0)  ==>  +inf.0
(* +inf.0 -inf.0)  ==>  -inf.0
(+ +inf.0 x)  ==>  +inf.0           ; provided x neither infinite nor NaN
(+ -inf.0 x)  ==>  -inf.0           ; provided x neither infinite nor NaN
(- +inf.0 +inf.0)  ==>  +nan.0      ; should be unspecified
(/ 0.0)  ==>  +inf.0
(/ 1.0 0)  ==>  +inf.0
(/ -1 0.0)  ==>  -inf.0
(/ +inf.0)  ==>  0.0                ; should be unspecified
(abs -inf.0)  ==>  +inf.0           ; should be unspecified, I think
(floor +inf.0)  ==>  +inf.0         ; should be unspecified or "is an error"
(ceiling -inf.0)  ==>  -inf.0       ; should be unspecified or "is an error"
(rationalize +inf.0 3)  ==>  +inf.0 ; should be unspecified
(rationalize +inf.0 +inf.0)  ==>  +nan.0
(rationalize 3 +inf.0)  ==>  0      ; should be 0.0
(exp +inf.0)  ==>  +inf.0
(exp -inf.0)  ==>  0.0
(log +inf.0)  ==>  +inf.0           ; should be unspecified
(log 0.0)  ==>  -inf.0
(log -inf.0)  ==>  +inf.0+pii
(atan -inf.0)  ==>  -1.5707963267948966  ; depends on precision etc
(atan +inf.0)  ==>  1.5707963267948966   ; depends on precision etc
(sqrt +inf.0)  ==>  +inf.0          ; should be unspecified
(sqrt -inf.0)  ==>  +inf.0i
(magnitude (make-rectangular x1 x2))  ==>  +inf.0  ; if x1 or x2 infinity
(angle +inf.0)  ==>  0.0
(angle -inf.0)  ==>  pi

The following behavior is strongly encouraged but not required:

(fl= +nan.0 +nan.0)  ==>  #f

Many of the examples above that are marked "should be unspecified"
should be strongly encouraged but not required:

(rational? +nan.0)  ==>  #f
(rational-valued? +nan.0)  ==>  #f
(+ +nan.0 x)  ==>  +nan.0
(* +nan.0 x)  ==>  +nan.0
(rational? -inf.0)  ==>  #f
(rational-valued? -inf.0)  ==>  #f
(fldenominator +inf.0)  ==>  1.0
(fldenominator -inf.0)  ==>  1.0
(flfloor +inf.0)  ==>  +inf.0
(flceiling -inf.0)  ==>  -inf.0
(fllog +inf.0)  ==>  +inf.0
(flsqrt +inf.0)  ==>  +inf.0
(+ +inf.0 -inf.0)  ==>  +nan.0
(- +inf.0 +inf.0)  ==>  +nan.0
(/ +inf.0)  ==>  0.0
(abs -inf.0)  ==>  +inf.0
(floor +inf.0)  ==>  +inf.0
(ceiling -inf.0)  ==>  -inf.0
(rationalize +inf.0 3)  ==>  +inf.0
(log +inf.0)  ==>  +inf.0
(sqrt +inf.0)  ==>  +inf.0

Finally, requiring 0 = (* 0 x) = (* x 0) is a change from R5RS.
Although many Scheme programmers have wanted this for years,
there are many other Scheme programmers who don't want it.
We should discuss this some more.

Will

```