1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-20 11:40:18 +02:00

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.
This commit is contained in:
Mark H Weaver 2011-01-28 23:32:20 -05:00 committed by Andy Wingo
parent 2e6e1933b4
commit c960e55600
4 changed files with 74 additions and 65 deletions

18
NEWS
View file

@ -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

View file

@ -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.
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.
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.
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}).
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 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?}.
Dividing zero by zero yields something that is not a number at all:
@samp{+nan.0}. This is the special `not a number' value.
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

View 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))
if (SCM_I_INUMP (x) || SCM_BIGP (x))
return SCM_BOOL_T;
if (SCM_IMP (x))
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 (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))
return SCM_BOOL_F;
if (r == floor (r))
return SCM_BOOL_T;
return SCM_BOOL_F;
}
#undef FUNC_NAME

View file

@ -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")))