>From ee5315abcbd527613caea504f738136d0e58274e Mon Sep 17 00:00:00 2001 From: Mark H Weaver Date: Fri, 28 Jan 2011 23:32:20 -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. 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 | 18 +++++++--- doc/ref/api-data.texi | 73 ++++++++++++++++++++++------------------- libguile/numbers.c | 40 +++++++--------------- test-suite/tests/numbers.test | 12 ++++++- 4 files changed, 76 insertions(+), 67 deletions(-) diff --git a/NEWS b/NEWS index 2979849..5651b17 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,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 diff --git a/doc/ref/api-data.texi b/doc/ref/api-data.texi index a0ab258..4256e18 100755 --- a/doc/ref/api-data.texi +++ b/doc/ref/api-data.texi @@ -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, 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. - - -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, 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. -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: address@hidden 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 address@hidden; @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 address@hidden 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}, address@hidden and @samp{-inf.0}. This syntax is also recognized by address@hidden 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 address@hidden 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 diff --git a/libguile/numbers.c b/libguile/numbers.c index 8513fea..608cf7a 100644 --- a/libguile/numbers.c +++ b/libguile/numbers.c @@ -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 diff --git a/test-suite/tests/numbers.test b/test-suite/tests/numbers.test index d116b6f..36e3128 100644 --- a/test-suite/tests/numbers.test +++ b/test-suite/tests/numbers.test @@ -1505,6 +1505,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"))) @@ -1515,7 +1520,7 @@ (pass-if (not (real? (current-input-port))))) ;;; -;;; rational? (same as real? right now) +;;; rational? ;;; (with-test-prefix "rational?" @@ -1526,6 +1531,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