distinguishing usual numbers, infinities and NaN

In a Scheme program, I need to distinguish infinities and NaN values. In Guile, it’s simple, it’s just the functions inf? and nan?. But when I took another implementation, I got troubles. I spent a lot of time and tried everything — =, eq?, equal?, but nothing helped. Fortunately, after a break, I found a simple universal solution.

Let’s see what happens if we compare (by <) the values.

Code:

(for-each (lambda (left)
    (for-each (lambda (right)
        (display (< left right))(display " "))
      (list (/ 0.0 0.0) (/ 1.0 0.0) (/ -1.0 0.0) 777))
    (newline))
  (list (/ 0.0 0.0) (/ 1.0 0.0) (/ -1.0 0.0) 777))

The table:

  <   | NaN +inf -inf 777
-------------------------
NaN   |  #f  #f   #f  #f
+inf  |  #f  #f   #f  #f
-inf  |  #f  #t   #f  #t
777   |  #f  #t   #f  #f

Similar tables can be got for > and =. With this table, it’s easy to differentiate the type of a variable x. For example:

* If it is greater than -inf and less that +inf, it’s an usual number.
* Otherwise: if it is greater than -inf, then it’s +inf; if it is less than +inf, then it’s -inf.
* Otherwise, it’s NaN.

The code uses another algorithm of the same style.

(define gx:nan? (lambda (x) (not (or (< x 777) (> x -777)))))
(define gx:inf? (lambda (x)
                      (if (and (< x (/ 1.0 0.0)) (> x (/ -1.0 0.0)))
                        #f
                        (not (gx:nan? x)))))

Testing:

(map gx:inf? (list (/ 0.0 0.0) (/ 1.0 0.0) (/ -1.0 0.0) 777))
    ===> (#f #t #t #f)

(map gx:nan? (list (/ 0.0 0.0) (/ 1.0 0.0) (/ -1.0 0.0) 777))
    ===> (#t #f #f #f)

One Response to “distinguishing usual numbers, infinities and NaN”

  1. olpa Says:

    I’ve got an e-mail reply from Kalle Olavi Niemitalo :


    Apparently R5RS does not require support for infinities,
    but if there is such support, I think these should work:

    (define (nan? x) (not (= x x)))
    (define (inf? x) (and (nan? (- x x)) (not (nan? x))))

    I like how there are no numerals in these.

    It’s a nice idea, I didn’t thought about it.

    Unfortunately, SISC interpreter has a bug. (= (/ 0.0 0.0) (/ 0.0 0.0)) is #t.

Leave a Reply