Infinities and NaNs are no longer rational
authorMark H Weaver <mhw@netris.org>
Sat, 29 Jan 2011 04:32:20 +0000 (23:32 -0500)
committerAndy Wingo <wingo@pobox.com>
Sun, 30 Jan 2011 12:08:53 +0000 (13:08 +0100)
* libguile/numbers.c (scm_rational_p): Return #f for infinities and
  NaNs, per R6RS.  Previously it returned #t for real infinities
  and NaNs.  They are still considered real by scm_real `real?'
  however, per R6RS.  Also simplify the code.

  (scm_real_p): New implementation to reflect the fact that the
  rationals and reals are no longer the same set.  Previously it just
  called scm_rational_p.

  (scm_integer_p): Simplify the code.

* test-suite/tests/numbers.test: Add test cases for `rational?'
  and `real?' applied to infinities and NaNs.

* doc/ref/api-data.texi (Real and Rational Numbers): Update docs to
  reflect the fact that infinities and NaNs are no longer rational, and
  that `real?'  no longer implies `rational?'.  Improve discussion of
  infinities and NaNs.

* NEWS: Add NEWS entries, and combine with an earlier entry about
  infinities no longer being integers.

NEWS
doc/ref/api-data.texi
libguile/numbers.c
test-suite/tests/numbers.test

diff --git a/NEWS b/NEWS
index 2979849..5651b17 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -27,11 +27,6 @@ Previously, `(equal? +nan.0 +nan.0)' returned #f, although
 both returned #t.  R5RS requires that `equal?' behave like
 `eqv?' when comparing numbers.
 
-*** Infinities are no longer integers.
-
-Following the R6RS, infinities (+inf.0 and -inf.0) are no longer
-considered to be integers.
-
 *** `expt' and `integer-expt' changes when the base is 0
 
 While `(expt 0 0)' is still 1, and `(expt 0 N)' for N > 0 is still
@@ -40,6 +35,19 @@ integer-expt.  This is more correct, and conforming to R6RS, but seems
 to be incompatible with R5RS, which would return 0 for all non-zero
 values of N.
 
+*** Infinities are no longer integers, nor rationals
+
+scm_integer_p `integer?' and scm_rational_p `rational?' now return #f
+for infinities, per R6RS.  Previously they returned #t for real
+infinities.  The real infinities and NaNs are still considered real by
+scm_real `real?' however, per R6RS.
+
+*** NaNs are no longer rationals
+
+scm_rational_p `rational?' now returns #f for NaN values, per R6RS.
+Previously it returned #t for real NaN values.  They are still
+considered real by scm_real `real?' however, per R6RS.
+
 *** `inf?' and `nan?' now throw exceptions for non-reals
 
 The domain of `inf?' and `nan?' is the real numbers.  Guile now signals
index a0ab258..4256e18 100755 (executable)
@@ -492,10 +492,10 @@ are not rational, for example @m{\sqrt2, the square root of 2}, and
 @m{\pi,pi}.
 
 Guile can represent both exact and inexact rational numbers, but it
-can not represent irrational numbers.  Exact rationals are represented
-by storing the numerator and denominator as two exact integers.
-Inexact rationals are stored as floating point numbers using the C
-type @code{double}.
+cannot represent precise finite irrational numbers.  Exact rationals are
+represented by storing the numerator and denominator as two exact
+integers.  Inexact rationals are stored as floating point numbers using
+the C type @code{double}.
 
 Exact rationals are written as a fraction of integers.  There must be
 no whitespace around the slash:
@@ -518,26 +518,41 @@ example:
 4.0
 @end lisp
 
-The limited precision of Guile's encoding means that any ``real'' number
-in Guile can be written in a rational form, by multiplying and then dividing
-by sufficient powers of 10 (or in fact, 2).  For example,
-@samp{-0.00000142857931198} is the same as @minus{}142857931198 divided by
-100000000000000000.  In Guile's current incarnation, therefore, the
-@code{rational?} and @code{real?} predicates are equivalent.
-
-
-Dividing by an exact zero leads to a error message, as one might
-expect.  However, dividing by an inexact zero does not produce an
-error.  Instead, the result of the division is either plus or minus
-infinity, depending on the sign of the divided number.
+The limited precision of Guile's encoding means that any finite ``real''
+number in Guile can be written in a rational form, by multiplying and
+then dividing by sufficient powers of 10 (or in fact, 2).  For example,
+@samp{-0.00000142857931198} is the same as @minus{}142857931198 divided
+by 100000000000000000.  In Guile's current incarnation, therefore, the
+@code{rational?} and @code{real?} predicates are equivalent for finite
+numbers.
 
-The infinities are written @samp{+inf.0} and @samp{-inf.0},
-respectively.  This syntax is also recognized by @code{read} as an
-extension to the usual Scheme syntax.  The infinities are considered to
-be inexact, non-integer values.
 
-Dividing zero by zero yields something that is not a number at all:
-@samp{+nan.0}.  This is the special `not a number' value.
+Dividing by an exact zero leads to a error message, as one might expect.
+However, dividing by an inexact zero does not produce an error.
+Instead, the result of the division is either plus or minus infinity,
+depending on the sign of the divided number and the sign of the zero
+divisor (some platforms support signed zeroes @samp{-0.0} and
+@samp{+0.0}; @samp{0.0} is the same as @samp{+0.0}).
+
+Dividing zero by an inexact zero yields a @acronym{NaN} (`not a number')
+value, although they are actually considered numbers by Scheme.
+Attempts to compare a @acronym{NaN} value with any number (including
+itself) using @code{=}, @code{<}, @code{>}, @code{<=} or @code{>=}
+always returns @code{#f}.  Although a @acronym{NaN} value is not
+@code{=} to itself, it is both @code{eqv?} and @code{equal?} to itself
+and other @acronym{NaN} values.  However, the preferred way to test for
+them is by using @code{nan?}.
+
+The real @acronym{NaN} values and infinities are written @samp{+nan.0},
+@samp{+inf.0} and @samp{-inf.0}.  This syntax is also recognized by
+@code{read} as an extension to the usual Scheme syntax.  These special
+values are considered by Scheme to be inexact real numbers but not
+rational.  Note that non-real complex numbers may also contain
+infinities or @acronym{NaN} values in their real or imaginary parts.  To
+test a real number to see if it is infinite, a @acronym{NaN} value, or
+neither, use @code{inf?}, @code{nan?}, or @code{finite?}, respectively.
+Every real number in Scheme belongs to precisely one of those three
+classes.
 
 On platforms that follow @acronym{IEEE} 754 for their floating point
 arithmetic, the @samp{+inf.0}, @samp{-inf.0}, and @samp{+nan.0} values
@@ -545,13 +560,6 @@ are implemented using the corresponding @acronym{IEEE} 754 values.
 They behave in arithmetic operations like @acronym{IEEE} 754 describes
 it, i.e., @code{(= +nan.0 +nan.0)} @result{} @code{#f}.
 
-While @samp{+nan.0} is not @code{=} to itself, it is @code{eqv?} to
-itself.
-
-To test for the special values, use the functions @code{inf?} and
-@code{nan?}.  To test for numbers than are neither infinite nor a NaN,
-use @code{finite?}.
-
 @deffn {Scheme Procedure} real? obj
 @deffnx {C Function} scm_real_p (obj)
 Return @code{#t} if @var{obj} is a real number, else @code{#f}.  Note
@@ -566,9 +574,6 @@ Return @code{#t} if @var{x} is a rational number, @code{#f} otherwise.
 Note that the set of integer values forms a subset of the set of
 rational numbers, i. e. the predicate will also be fulfilled if
 @var{x} is an integer number.
-
-Since Guile can not represent irrational numbers, every number
-satisfying @code{real?} also satisfies @code{rational?} in Guile.
 @end deffn
 
 @deffn {Scheme Procedure} rationalize x eps
@@ -607,12 +612,12 @@ NaN, @code{#f} otherwise.
 
 @deffn {Scheme Procedure} nan
 @deffnx {C Function} scm_nan ()
-Return NaN.
+Return @samp{+nan.0}, a @acronym{NaN} value.
 @end deffn
 
 @deffn {Scheme Procedure} inf
 @deffnx {C Function} scm_inf ()
-Return Inf.
+Return @samp{+inf.0}, positive infinity.
 @end deffn
 
 @deffn {Scheme Procedure} numerator x
index 8513fea..608cf7a 100644 (file)
@@ -3281,8 +3281,8 @@ SCM_DEFINE (scm_real_p, "real?", 1, 0, 0,
            "fulfilled if @var{x} is an integer number.")
 #define FUNC_NAME s_scm_real_p
 {
-  /* we can't represent irrational numbers. */
-  return scm_rational_p (x);
+  return scm_from_bool
+    (SCM_I_INUMP (x) || SCM_REALP (x) || SCM_BIGP (x) || SCM_FRACTIONP (x));
 }
 #undef FUNC_NAME
 
@@ -3294,18 +3294,12 @@ SCM_DEFINE (scm_rational_p, "rational?", 1, 0, 0,
            "fulfilled if @var{x} is an integer number.")
 #define FUNC_NAME s_scm_rational_p
 {
-  if (SCM_I_INUMP (x))
-    return SCM_BOOL_T;
-  else if (SCM_IMP (x))
-    return SCM_BOOL_F;
-  else if (SCM_BIGP (x))
-    return SCM_BOOL_T;
-  else if (SCM_FRACTIONP (x))
+  if (SCM_I_INUMP (x) || SCM_BIGP (x) || SCM_FRACTIONP (x))
     return SCM_BOOL_T;
   else if (SCM_REALP (x))
-    /* due to their limited precision, all floating point numbers are
-       rational as well. */
-    return SCM_BOOL_T;
+    /* due to their limited precision, finite floating point numbers are
+       rational as well. (finite means neither infinity nor a NaN) */
+    return scm_from_bool (DOUBLE_IS_FINITE (SCM_REAL_VALUE (x)));
   else
     return SCM_BOOL_F;
 }
@@ -3317,23 +3311,15 @@ SCM_DEFINE (scm_integer_p, "integer?", 1, 0, 0,
            "else.")
 #define FUNC_NAME s_scm_integer_p
 {
-  double r;
-  if (SCM_I_INUMP (x))
-    return SCM_BOOL_T;
-  if (SCM_IMP (x))
-    return SCM_BOOL_F;
-  if (SCM_BIGP (x))
+  if (SCM_I_INUMP (x) || SCM_BIGP (x))
     return SCM_BOOL_T;
-  if (!SCM_INEXACTP (x))
-    return SCM_BOOL_F;
-  if (SCM_COMPLEXP (x))
-    return SCM_BOOL_F;
-  r = SCM_REAL_VALUE (x);
-  if (isinf (r))
+  else if (SCM_REALP (x))
+    {
+      double val = SCM_REAL_VALUE (x);
+      return scm_from_bool (!isinf (val) && (val == floor (val)));
+    }
+  else
     return SCM_BOOL_F;
-  if (r == floor (r))
-    return SCM_BOOL_T;
-  return SCM_BOOL_F;
 }
 #undef FUNC_NAME
 
index d116b6f..36e3128 100644 (file)
   (pass-if (real? (+ 1 fixnum-max)))
   (pass-if (real? (- 1 fixnum-min)))
   (pass-if (real? 1.3))
+  (pass-if (real? +inf.0))
+  (pass-if (real? -inf.0))
+  (pass-if (real? +nan.0))
+  (pass-if (not (real? +inf.0-inf.0i)))
+  (pass-if (not (real? +nan.0+nan.0i)))
   (pass-if (not (real? 3+4i)))
   (pass-if (not (real? #\a)))
   (pass-if (not (real? "a")))
   (pass-if (not (real? (current-input-port)))))
 
 ;;;
-;;; rational? (same as real? right now)
+;;; rational?
 ;;;
 
 (with-test-prefix "rational?"
   (pass-if (rational? (+ 1 fixnum-max)))
   (pass-if (rational? (- 1 fixnum-min)))
   (pass-if (rational? 1.3))
+  (pass-if (not (rational? +inf.0)))
+  (pass-if (not (rational? -inf.0)))
+  (pass-if (not (rational? +nan.0)))
+  (pass-if (not (rational? +inf.0-inf.0i)))
+  (pass-if (not (rational? +nan.0+nan.0i)))
   (pass-if (not (rational? 3+4i)))
   (pass-if (not (rational? #\a)))
   (pass-if (not (rational? "a")))