diff options
author | matz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2006-09-14 08:23:28 +0000 |
---|---|---|
committer | matz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2006-09-14 08:23:28 +0000 |
commit | 49f0e92f2889de1923f022ea52758340d3f29787 (patch) | |
tree | a1c0d9a5f7136c2ad1c0773cc7e6d9a4efd77513 /numeric.c | |
parent | 2a23c281a1d7d61b866cb01867dbe5ebff1e2263 (diff) | |
download | ruby-49f0e92f2889de1923f022ea52758340d3f29787.tar.gz |
* numeric.c (fix_mul): avoid bignum multiplication as far as
possible. a patch from Ondrej Bilka <neleai at seznam.cz>.
[ruby-core:08825]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@10934 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'numeric.c')
-rw-r--r-- | numeric.c | 22 |
1 files changed, 19 insertions, 3 deletions
@@ -1973,20 +1973,36 @@ fix_mul(VALUE x, VALUE y) /* avoids an optimization bug of HP aC++/ANSI C B3910B A.06.05 [Jul 25 2005] */ volatile #endif - long a, b, c; + SIGNED_VALUE a, b; +#if SIZEOF_VALUE * 2 <= SIZEOF_LONG_LONG + LONG_LONG d; +#else + SIGNED_VALUE c; VALUE r; +#endif a = FIX2LONG(x); - if (a == 0) return x; - b = FIX2LONG(y); + +#if SIZEOF_VALUE * 2 <= SIZEOF_LONG_LONG + d = (LONG_LONG)a * b; + if (FIXABLE(d)) return LONG2FIX(d); + return rb_ll2inum(d); +#else +# define SQRT_LONG_MAX (1<<((SIZEOF_VALUE*CHAR_BIT-1)/2)) + /*tests if N*N would overflow*/ +# define FIT_SQRT_LONG(n) (((n)<SQRT_LONG_MAX)&&((N)>=-SQRT_LONG_MAX)) + if (FIT_SQRT_LONG(a) && FIT_SQRT_LONG(b)) + return LONG2FIX(a*b); c = a * b; r = LONG2FIX(c); + if (a == 0) return x; if (FIX2LONG(r) != c || c/a != b) { r = rb_big_mul(rb_int2big(a), rb_int2big(b)); } return r; +#endif } switch (TYPE(y)) { case T_BIGNUM: |