diff options
author | Andy Wingo <wingo@pobox.com> | 2017-02-28 10:12:57 +0100 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2017-02-28 10:12:57 +0100 |
commit | 70d4c4b284ba85d89969d8da43f80ff66f491e37 (patch) | |
tree | 0bfb940edaae9023a281c10a8b21a4eb35b09e4e /libguile | |
parent | f8dd4f67b5af9e80642a6b262f96049690a3e8bf (diff) |
Fix (* x -1) for GOOPS types
* libguile/numbers.c (scm_product): Only reduce (* x -1) to (- x) when X
is a bignum. Fixes weirdness when X is not a number and instead
multiplication should dispatch to GOOPS. Thanks to Alejandro Sanchez
for the report.
Diffstat (limited to 'libguile')
-rw-r--r-- | libguile/numbers.c | 28 |
1 files changed, 13 insertions, 15 deletions
diff --git a/libguile/numbers.c b/libguile/numbers.c index 99b564e95..0d053c867 100644 --- a/libguile/numbers.c +++ b/libguile/numbers.c @@ -8021,17 +8021,6 @@ scm_product (SCM x, SCM y) else return scm_wta_dispatch_2 (g_product, x, y, SCM_ARGn, s_product); break; - case -1: - /* - * This case 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))) - */ - return scm_difference(y, SCM_UNDEFINED); - break; } if (SCM_LIKELY (SCM_I_INUMP (y))) @@ -8056,10 +8045,19 @@ scm_product (SCM x, SCM y) } else if (SCM_BIGP (y)) { - SCM result = scm_i_mkbig (); - mpz_mul_si (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (y), xx); - scm_remember_upto_here_1 (y); - return result; + /* There is one bignum which, when multiplied by negative one, + becomes a non-zero fixnum: (1+ most-positive-fixum). Since + we know the type of X and Y are numbers, delegate this + special case to scm_difference. */ + if (xx == -1) + return scm_difference (y, SCM_UNDEFINED); + else + { + SCM result = scm_i_mkbig (); + mpz_mul_si (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (y), xx); + scm_remember_upto_here_1 (y); + return result; + } } else if (SCM_REALP (y)) return scm_i_from_double (xx * SCM_REAL_VALUE (y)); |