mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-20 11:40:18 +02:00
Fix bugs when negating SCM_MOST_POSITIVE_FIXNUM+1
* libguile/numbers.c (scm_difference, scm_product): Fix bugs when negating SCM_MOST_POSITIVE_FIXNUM+1, aka -SCM_MOST_NEGATIVE_FIXNUM. Previously, these cases failed to normalize the result to a fixnum, causing `=', `eqv?' and `equal?' to fail, e.g.: (= most-negative-fixnum (- 0 (- most-negative-fixnum))) (= most-negative-fixnum (* -1 (- most-negative-fixnum))) (= most-negative-fixnum (* (- most-negative-fixnum) -1)) * test-suite/test/numbers.test: Add test cases to detect bugs when negating SCM_MOST_POSITIVE_FIXNUM+1 and SCM_MOST_NEGATIVE_FIXNUM by various methods.
This commit is contained in:
parent
425d55f969
commit
b5c40589ec
2 changed files with 43 additions and 1 deletions
|
@ -4488,7 +4488,11 @@ scm_difference (SCM x, SCM y)
|
|||
scm_t_inum xx = SCM_I_INUM (x);
|
||||
|
||||
if (xx == 0)
|
||||
return scm_i_clonebig (y, 0);
|
||||
{
|
||||
/* Must scm_i_normbig here because -SCM_MOST_NEGATIVE_FIXNUM is a
|
||||
bignum, but negating that gives a fixnum. */
|
||||
return scm_i_normbig (scm_i_clonebig (y, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
int sgn_y = mpz_sgn (SCM_I_BIG_MPZ (y));
|
||||
|
@ -4720,6 +4724,17 @@ scm_product (SCM x, SCM y)
|
|||
{
|
||||
case 0: return x; break;
|
||||
case 1: return y; break;
|
||||
/*
|
||||
* The following case (x = -1) is important for more than
|
||||
* just optimization. It handles the case of negating
|
||||
* (+ 1 most-positive-fixnum) aka (- most-negative-fixnum),
|
||||
* which is a bignum that must be changed back into a fixnum.
|
||||
* Failure to do so will cause the following to return #f:
|
||||
* (= most-negative-fixnum (* -1 (- most-negative-fixnum)))
|
||||
*/
|
||||
case -1:
|
||||
return scm_difference(y, SCM_UNDEFINED);
|
||||
break;
|
||||
}
|
||||
|
||||
if (SCM_LIKELY (SCM_I_INUMP (y)))
|
||||
|
|
|
@ -2525,6 +2525,20 @@
|
|||
|
||||
(with-test-prefix/c&e "-"
|
||||
|
||||
(pass-if "double-negation of fixnum-min: ="
|
||||
(= fixnum-min (- (- fixnum-min))))
|
||||
(pass-if "double-negation of fixnum-min: eqv?"
|
||||
(eqv? fixnum-min (- (- fixnum-min))))
|
||||
(pass-if "double-negation of fixnum-min: equal?"
|
||||
(equal? fixnum-min (- (- fixnum-min))))
|
||||
|
||||
(pass-if "binary double-negation of fixnum-min: ="
|
||||
(= fixnum-min (- 0 (- 0 fixnum-min))))
|
||||
(pass-if "binary double-negation of fixnum-min: eqv?"
|
||||
(eqv? fixnum-min (- 0 (- 0 fixnum-min))))
|
||||
(pass-if "binary double-negation of fixnum-min: equal?"
|
||||
(equal? fixnum-min (- 0 (- 0 fixnum-min))))
|
||||
|
||||
(pass-if "-inum - +bignum"
|
||||
(= #x-100000000000000000000000000000001
|
||||
(- -1 #x100000000000000000000000000000000)))
|
||||
|
@ -2554,6 +2568,14 @@
|
|||
|
||||
(with-test-prefix "*"
|
||||
|
||||
(with-test-prefix "double-negation of fixnum-min"
|
||||
(pass-if (= fixnum-min (* -1 (* -1 fixnum-min))))
|
||||
(pass-if (eqv? fixnum-min (* -1 (* -1 fixnum-min))))
|
||||
(pass-if (equal? fixnum-min (* -1 (* -1 fixnum-min))))
|
||||
(pass-if (= fixnum-min (* (* fixnum-min -1) -1)))
|
||||
(pass-if (eqv? fixnum-min (* (* fixnum-min -1) -1)))
|
||||
(pass-if (equal? fixnum-min (* (* fixnum-min -1) -1))))
|
||||
|
||||
(with-test-prefix "inum * bignum"
|
||||
|
||||
(pass-if "0 * 2^256 = 0"
|
||||
|
@ -2607,6 +2629,11 @@
|
|||
|
||||
(with-test-prefix "/"
|
||||
|
||||
(with-test-prefix "double-negation of fixnum-min"
|
||||
(pass-if (= fixnum-min (/ (/ fixnum-min -1) -1)))
|
||||
(pass-if (eqv? fixnum-min (/ (/ fixnum-min -1) -1)))
|
||||
(pass-if (equal? fixnum-min (/ (/ fixnum-min -1) -1))))
|
||||
|
||||
(pass-if "documented?"
|
||||
(documented? /))
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue