>From 6d2d6566539e5eec70310113aee14a5ba8fb51e7 Mon Sep 17 00:00:00 2001 From: Mark H Weaver Date: Wed, 26 Jan 2011 16:44:57 -0500 Subject: [PATCH] Infinities and NaNs are no longer rational * 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. * 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 that infinities and NaNs are irrational, and that `real?' no longer implies `rational?'. * NEWS: Add NEWS entries, and combine with an earlier entry about infinities no longer being integers. --- NEWS | 23 ++++++++++++++++++----- doc/ref/api-data.texi | 38 +++++++++++++++++++------------------- libguile/numbers.c | 20 +++++++++++++++----- test-suite/tests/numbers.test | 12 +++++++++++- 4 files changed, 63 insertions(+), 30 deletions(-) diff --git a/NEWS b/NEWS index 8153d0e..13d90a5 100644 --- 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,24 @@ 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. Note that non-real complex +numbers may contain infinities in their real or complex parts. Such +numbers are not real. + +*** 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. Note that +non-real complex numbers may contain NaNs in their real or complex +parts. Such numbers are not real. In fact it is possible for a +non-real complex number to be both a NaN and infinite. + *** `inf?' and `nan?' now throw exceptions for non-numbers scm_inf_p `inf?' and scm_nan_p `nan?' now throw exceptions if passed diff --git a/doc/ref/api-data.texi b/doc/ref/api-data.texi index f2a03b3..ce08584 100755 --- a/doc/ref/api-data.texi +++ b/doc/ref/api-data.texi @@ -491,11 +491,11 @@ All rational numbers are also real, but there are real numbers that 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}. +Guile can represent both exact and inexact rational numbers, but it can +not 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,12 +518,13 @@ 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, address@hidden is the same as @minus{}142857931198 divided by -100000000000000000. In Guile's current incarnation, therefore, the address@hidden and @code{real?} predicates are equivalent. +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, address@hidden is the same as @minus{}142857931198 divided +by 100000000000000000. In Guile's current incarnation, therefore, the address@hidden and @code{real?} predicates are equivalent for finite +numbers. Dividing by an exact zero leads to a error message, as one might expect. @@ -542,12 +543,11 @@ is both @code{eqv?} and @code{equal?} to itself. The best way to test for them is by using @code{nan?}, which also detects complex numbers whose real or imaginary part is a @acronym{NaN}. -These special values are written @samp{+nan.0}, @samp{+inf.0} and address@hidden 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. @acronym{NaN} values are considered to -be inexact and irrational. To test for numbers that are neither -infinite nor a @acronym{NaN}, use @code{finite?}. +The real infinities and NaNs 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. All three of these special values +are considered to be inexact, irrational reals. To test for numbers +that are neither infinite nor a @acronym{NaN}, use @code{finite?}. On platforms that follow @acronym{IEEE} 754 for their floating point arithmetic, the @samp{+inf.0}, @samp{-inf.0}, and @samp{+nan.0} values @@ -570,8 +570,8 @@ 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. +The only irrational real numbers representable by Guile are address@hidden, @samp{-inf.0}, and @samp{+nan.0}. @end deffn @deffn {Scheme Procedure} rationalize x eps diff --git a/libguile/numbers.c b/libguile/numbers.c index bfa6c22..bfe3699 100644 --- a/libguile/numbers.c +++ b/libguile/numbers.c @@ -3292,8 +3292,18 @@ 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); + 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)) + return SCM_BOOL_T; + else if (SCM_REALP (x)) + return SCM_BOOL_T; + else + return SCM_BOOL_F; } #undef FUNC_NAME @@ -3313,9 +3323,9 @@ SCM_DEFINE (scm_rational_p, "rational?", 1, 0, 0, return SCM_BOOL_T; else if (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. */ + else if (SCM_REALP (x) && SCM_I_CDBL_IS_FINITE (SCM_REAL_VALUE (x))) + /* due to their limited precision, finite floating point numbers are + rational as well. (finite means neither infinity nor a NaN) */ return SCM_BOOL_T; else return SCM_BOOL_F; diff --git a/test-suite/tests/numbers.test b/test-suite/tests/numbers.test index 2d20ef2..8851068 100644 --- a/test-suite/tests/numbers.test +++ b/test-suite/tests/numbers.test @@ -1494,6 +1494,11 @@ (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"))) @@ -1504,7 +1509,7 @@ (pass-if (not (real? (current-input-port))))) ;;; -;;; rational? (same as real? right now) +;;; rational? ;;; (with-test-prefix "rational?" @@ -1515,6 +1520,11 @@ (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"))) -- 1.5.6.5