diff --git a/libguile/integers.c b/libguile/integers.c index e449ff635..34a1d4af8 100644 --- a/libguile/integers.c +++ b/libguile/integers.c @@ -244,3 +244,25 @@ scm_is_integer_odd_z (SCM z) { return bignum_limbs (scm_bignum (z))[0] & 1; } + +SCM +scm_integer_abs_i (scm_t_inum i) +{ + if (i >= 0) + return SCM_I_MAKINUM (i); + + unsigned long abs = long_magnitude (i); + if (SCM_LIKELY (SCM_POSFIXABLE (abs))) + return SCM_I_MAKINUM (abs); + + return ulong_to_bignum (abs); +} + +SCM +scm_integer_abs_z (SCM z) +{ + if (!bignum_is_negative (scm_bignum (z))) + return z; + + return SCM_PACK (negate_bignum (clone_bignum (scm_bignum (z)))); +} diff --git a/libguile/integers.h b/libguile/integers.h index 2bd937669..753ff1f74 100644 --- a/libguile/integers.h +++ b/libguile/integers.h @@ -26,6 +26,9 @@ SCM_INTERNAL int scm_is_integer_odd_i (scm_t_inum i); SCM_INTERNAL int scm_is_integer_odd_z (SCM z); +SCM_INTERNAL SCM scm_integer_abs_i (scm_t_inum i); +SCM_INTERNAL SCM scm_integer_abs_z (SCM z); + #endif /* SCM_INTEGERS_H */ diff --git a/libguile/numbers.c b/libguile/numbers.c index a91d5963d..ea0cf67bb 100644 --- a/libguile/numbers.c +++ b/libguile/numbers.c @@ -919,15 +919,7 @@ SCM_PRIMITIVE_GENERIC (scm_abs, "abs", 1, 0, 0, #define FUNC_NAME s_scm_abs { if (SCM_I_INUMP (x)) - { - scm_t_inum xx = SCM_I_INUM (x); - if (xx >= 0) - return x; - else if (SCM_POSFIXABLE (-xx)) - return SCM_I_MAKINUM (-xx); - else - return scm_i_inum2big (-xx); - } + return scm_integer_abs_i (SCM_I_INUM (x)); else if (SCM_LIKELY (SCM_REALP (x))) { double xx = SCM_REAL_VALUE (x); @@ -941,13 +933,7 @@ SCM_PRIMITIVE_GENERIC (scm_abs, "abs", 1, 0, 0, return x; } else if (SCM_BIGP (x)) - { - const int sgn = mpz_sgn (SCM_I_BIG_MPZ (x)); - if (sgn < 0) - return scm_i_clonebig (x, 0); - else - return x; - } + return scm_integer_abs_z (x); else if (SCM_FRACTIONP (x)) { if (scm_is_false (scm_negative_p (SCM_FRACTION_NUMERATOR (x))))