mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-20 11:40:18 +02:00
Improve handling of signed zeroes
* libguile/numbers.c (scm_abs): (abs -0.0) now returns 0.0. Previously it returned -0.0. Also move the REALP case above the BIGP case, and consider it SCM_LIKELY to be REALP if not INUMP. (scm_difference): (- 0 0.0) now returns -0.0. Previously it returned 0.0. Also make sure that (- 0 0.0+0.0i) will return -0.0-0.0i. * test-suite/tests/numbers.test (abs, -): Add test cases, and change some tests to use `eqv?' instead of `=', in order to test exactness and distinguish signed zeroes.
This commit is contained in:
parent
8deddc948d
commit
9b9ef10cf0
2 changed files with 103 additions and 23 deletions
|
@ -745,6 +745,18 @@ SCM_PRIMITIVE_GENERIC (scm_abs, "abs", 1, 0, 0,
|
|||
else
|
||||
return scm_i_inum2big (-xx);
|
||||
}
|
||||
else if (SCM_LIKELY (SCM_REALP (x)))
|
||||
{
|
||||
double xx = SCM_REAL_VALUE (x);
|
||||
/* If x is a NaN then xx<0 is false so we return x unchanged */
|
||||
if (xx < 0.0)
|
||||
return scm_from_double (-xx);
|
||||
/* Handle signed zeroes properly */
|
||||
else if (SCM_UNLIKELY (xx == 0.0))
|
||||
return flo0;
|
||||
else
|
||||
return x;
|
||||
}
|
||||
else if (SCM_BIGP (x))
|
||||
{
|
||||
const int sgn = mpz_sgn (SCM_I_BIG_MPZ (x));
|
||||
|
@ -753,15 +765,6 @@ SCM_PRIMITIVE_GENERIC (scm_abs, "abs", 1, 0, 0,
|
|||
else
|
||||
return x;
|
||||
}
|
||||
else if (SCM_REALP (x))
|
||||
{
|
||||
/* note that if x is a NaN then xx<0 is false so we return x unchanged */
|
||||
double xx = SCM_REAL_VALUE (x);
|
||||
if (xx < 0.0)
|
||||
return scm_from_double (-xx);
|
||||
else
|
||||
return x;
|
||||
}
|
||||
else if (SCM_FRACTIONP (x))
|
||||
{
|
||||
if (scm_is_false (scm_negative_p (SCM_FRACTION_NUMERATOR (x))))
|
||||
|
@ -5758,13 +5761,35 @@ scm_difference (SCM x, SCM y)
|
|||
else if (SCM_REALP (y))
|
||||
{
|
||||
scm_t_inum xx = SCM_I_INUM (x);
|
||||
return scm_from_double (xx - SCM_REAL_VALUE (y));
|
||||
|
||||
/*
|
||||
* We need to handle x == exact 0
|
||||
* specially because R6RS states that:
|
||||
* (- 0.0) ==> -0.0 and
|
||||
* (- 0.0 0.0) ==> 0.0
|
||||
* and the scheme compiler changes
|
||||
* (- 0.0) into (- 0 0.0)
|
||||
* So we need to treat (- 0 0.0) like (- 0.0).
|
||||
* At the C level, (-x) is different than (0.0 - x).
|
||||
* (0.0 - 0.0) ==> 0.0, but (- 0.0) ==> -0.0.
|
||||
*/
|
||||
if (xx == 0)
|
||||
return scm_from_double (- SCM_REAL_VALUE (y));
|
||||
else
|
||||
return scm_from_double (xx - SCM_REAL_VALUE (y));
|
||||
}
|
||||
else if (SCM_COMPLEXP (y))
|
||||
{
|
||||
scm_t_inum xx = SCM_I_INUM (x);
|
||||
return scm_c_make_rectangular (xx - SCM_COMPLEX_REAL (y),
|
||||
- SCM_COMPLEX_IMAG (y));
|
||||
|
||||
/* We need to handle x == exact 0 specially.
|
||||
See the comment above (for SCM_REALP (y)) */
|
||||
if (xx == 0)
|
||||
return scm_c_make_rectangular (- SCM_COMPLEX_REAL (y),
|
||||
- SCM_COMPLEX_IMAG (y));
|
||||
else
|
||||
return scm_c_make_rectangular (xx - SCM_COMPLEX_REAL (y),
|
||||
- SCM_COMPLEX_IMAG (y));
|
||||
}
|
||||
else if (SCM_FRACTIONP (y))
|
||||
/* a - b/c = (ac - b) / c */
|
||||
|
|
|
@ -423,17 +423,23 @@
|
|||
|
||||
(with-test-prefix "abs"
|
||||
(pass-if (documented? abs))
|
||||
(pass-if (zero? (abs 0)))
|
||||
(pass-if (= 1 (abs 1)))
|
||||
(pass-if (= 1 (abs -1)))
|
||||
(pass-if (= (+ fixnum-max 1) (abs (+ fixnum-max 1))))
|
||||
(pass-if (= (+ (- fixnum-min) 1) (abs (- fixnum-min 1))))
|
||||
(pass-if (= 0.0 (abs 0.0)))
|
||||
(pass-if (= 1.0 (abs 1.0)))
|
||||
(pass-if (= 1.0 (abs -1.0)))
|
||||
(pass-if (real-nan? (abs +nan.0)))
|
||||
(pass-if (= +inf.0 (abs +inf.0)))
|
||||
(pass-if (= +inf.0 (abs -inf.0))))
|
||||
(pass-if (eqv? 0 (abs 0)))
|
||||
(pass-if (eqv? 1 (abs 1)))
|
||||
(pass-if (eqv? 1 (abs -1)))
|
||||
|
||||
(with-test-prefix "double-negation of fixnum-min"
|
||||
(pass-if (eqv? fixnum-min (- (abs fixnum-min)))))
|
||||
|
||||
(pass-if (eqv? (+ fixnum-max 1) (abs (+ fixnum-max 1))))
|
||||
(pass-if (eqv? (+ (- fixnum-min) 1) (abs (- fixnum-min 1))))
|
||||
|
||||
(pass-if (eqv? 0.0 (abs 0.0)))
|
||||
(pass-if (eqv? 0.0 (abs -0.0)))
|
||||
(pass-if (eqv? 1.0 (abs 1.0)))
|
||||
(pass-if (eqv? 1.0 (abs -1.0)))
|
||||
(pass-if (real-nan? (abs +nan.0)))
|
||||
(pass-if (eqv? +inf.0 (abs +inf.0)))
|
||||
(pass-if (eqv? +inf.0 (abs -inf.0))))
|
||||
|
||||
;;;
|
||||
;;; quotient
|
||||
|
@ -2814,6 +2820,55 @@
|
|||
(pass-if "binary double-negation of fixnum-min: equal?"
|
||||
(equal? fixnum-min (- 0 (- 0 fixnum-min))))
|
||||
|
||||
(pass-if "signed zeroes"
|
||||
(and (eqv? +0.0 (- -0.0))
|
||||
(eqv? -0.0 (- +0.0))
|
||||
(eqv? 0.0 (- 0.0 0.0))
|
||||
(eqv? 0.0 (- 0.0 -0.0))
|
||||
(eqv? 0.0 (- -0.0 -0.0))
|
||||
(eqv? -0.0 (- -0.0 0.0))))
|
||||
|
||||
(pass-if "exactness propagation"
|
||||
(and (eqv? 3 (- 8 5))
|
||||
(eqv? 3.0 (- 8 5.0))
|
||||
(eqv? 3.0 (- 8.0 5))
|
||||
(eqv? 3.0 (- 8.0 5.0))
|
||||
(eqv? -1/6 (- 1/3 1/2))
|
||||
(eqv? -4.5 (- 1/2 5.0))
|
||||
(eqv? 2.75 (- 3.0 1/4))))
|
||||
|
||||
(pass-if "infinities"
|
||||
(and (eqv? +inf.0 (- +inf.0 -inf.0))
|
||||
(eqv? -inf.0 (- -inf.0 +inf.0))
|
||||
(real-nan? (- +inf.0 +inf.0))
|
||||
(real-nan? (- -inf.0 -inf.0))))
|
||||
|
||||
(pass-if "NaNs"
|
||||
(and (real-nan? (- +nan.0 +nan.0))
|
||||
(real-nan? (- 0 +nan.0))
|
||||
(real-nan? (- +nan.0 0))
|
||||
(real-nan? (- 1 +nan.0))
|
||||
(real-nan? (- +nan.0 1))
|
||||
(real-nan? (- -1 +nan.0))
|
||||
(real-nan? (- +nan.0 -1))
|
||||
(real-nan? (- -7/2 +nan.0))
|
||||
(real-nan? (- +nan.0 -7/2))
|
||||
(real-nan? (- 1e20 +nan.0))
|
||||
(real-nan? (- +nan.0 1e20))
|
||||
(real-nan? (- +inf.0 +nan.0))
|
||||
(real-nan? (- +nan.0 +inf.0))
|
||||
(real-nan? (- -inf.0 +nan.0))
|
||||
(real-nan? (- +nan.0 -inf.0))
|
||||
(real-nan? (- (* fixnum-max 2) +nan.0))
|
||||
(real-nan? (- +nan.0 (* fixnum-max 2)))))
|
||||
|
||||
(pass-if "(eqv? fixnum-min (- (- fixnum-min)))"
|
||||
(eqv? fixnum-min (- (- fixnum-min))))
|
||||
(pass-if "(eqv? fixnum-min (- 0 (- 0 fixnum-min)))"
|
||||
(eqv? fixnum-min (- 0 (- 0 fixnum-min))))
|
||||
(pass-if "(eqv? fixnum-num (apply - (list (apply - (list fixnum-min)))))"
|
||||
(eqv? fixnum-min (apply - (list (apply - (list fixnum-min))))))
|
||||
|
||||
(pass-if "-inum - +bignum"
|
||||
(= #x-100000000000000000000000000000001
|
||||
(- -1 #x100000000000000000000000000000000)))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue