diff options
author | akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2013-04-09 11:39:53 +0000 |
---|---|---|
committer | akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2013-04-09 11:39:53 +0000 |
commit | 712c7168bf55f61df33efa2a7552e4b3c25b306c (patch) | |
tree | a8f7e877849ffca9db3de17e3fe783d367f25933 /bignum.c | |
parent | 4329b14cfbe4c91561c12ba7d1b40c66faea30b5 (diff) |
* internal.h (MUL_OVERFLOW_SIGNED_INTEGER_P): New macro.
(MUL_OVERFLOW_FIXNUM_P): Ditto.
(MUL_OVERFLOW_LONG_P): Ditto.
* array.c (rb_ary_product): Don't overflow on signed integer
multiplication.
* numeric.c (fix_mul): Ditto.
(int_pow): Ditto.
* rational.c (f_imul): Ditto.
* insns.def (opt_mult): Ditto.
* thread.c (sleep_timeval): Don't overflow on signed integer addition.
* bignum.c (rb_int2big): Don't overflow on signed integer negation.
(rb_big2ulong): Ditto.
(rb_big2long): Ditto.
(rb_big2ull): Ditto.
(rb_big2ll): Ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40208 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'bignum.c')
-rw-r--r-- | bignum.c | 71 |
1 files changed, 46 insertions, 25 deletions
@@ -309,13 +309,17 @@ VALUE rb_int2big(SIGNED_VALUE n) { long neg = 0; + VALUE u; VALUE big; if (n < 0) { - n = -n; + u = 1 + (VALUE)(-(n + 1)); /* u = -n avoiding overflow */ neg = 1; } - big = rb_uint2big(n); + else { + u = n; + } + big = rb_uint2big(u); if (neg) { RBIGNUM_SET_SIGN(big, 0); } @@ -1224,12 +1228,15 @@ rb_big2ulong(VALUE x) { VALUE num = big2ulong(x, "unsigned long", TRUE); - if (!RBIGNUM_SIGN(x)) { - unsigned long v = (unsigned long)(-(long)num); - - if (v <= LONG_MAX) - rb_raise(rb_eRangeError, "bignum out of range of unsigned long"); - return (VALUE)v; + if (RBIGNUM_POSITIVE_P(x)) { + return num; + } + else { + if (num <= LONG_MAX) + return -(long)num; + if (num == 1+(unsigned long)(-(LONG_MIN+1))) + return LONG_MIN; + rb_raise(rb_eRangeError, "bignum out of range of unsigned long"); } return num; } @@ -1239,12 +1246,18 @@ rb_big2long(VALUE x) { VALUE num = big2ulong(x, "long", TRUE); - if ((long)num < 0 && - (RBIGNUM_SIGN(x) || (long)num != LONG_MIN)) { - rb_raise(rb_eRangeError, "bignum too big to convert into `long'"); + if (RBIGNUM_POSITIVE_P(x)) { + if (LONG_MAX < num) + rb_raise(rb_eRangeError, "bignum too big to convert into `long'"); + return num; + } + else { + if (num <= LONG_MAX) + return -(long)num; + if (num == 1+(unsigned long)(-(LONG_MIN+1))) + return LONG_MIN; + rb_raise(rb_eRangeError, "bignum too big to convert into `long'"); } - if (!RBIGNUM_SIGN(x)) return -(SIGNED_VALUE)num; - return num; } #if HAVE_LONG_LONG @@ -1272,13 +1285,15 @@ rb_big2ull(VALUE x) { unsigned LONG_LONG num = big2ull(x, "unsigned long long"); - if (!RBIGNUM_SIGN(x)) { - LONG_LONG v = -(LONG_LONG)num; - - /* FIXNUM_MIN-1 .. LLONG_MIN mapped into 0xbfffffffffffffff .. LONG_MAX+1 */ - if ((unsigned LONG_LONG)v <= LLONG_MAX) - rb_raise(rb_eRangeError, "bignum out of range of unsigned long long"); - return v; + if (RBIGNUM_POSITIVE_P(x)) { + return num; + } + else { + if (num <= LLONG_MAX) + return -(LONG_LONG)num; + if (num == 1+(unsigned LONG_LONG)(-(LLONG_MIN+1))) + return LLONG_MIN; + rb_raise(rb_eRangeError, "bignum out of range of unsigned long long"); } return num; } @@ -1288,12 +1303,18 @@ rb_big2ll(VALUE x) { unsigned LONG_LONG num = big2ull(x, "long long"); - if ((LONG_LONG)num < 0 && (RBIGNUM_SIGN(x) - || (LONG_LONG)num != LLONG_MIN)) { - rb_raise(rb_eRangeError, "bignum too big to convert into `long long'"); + if (RBIGNUM_POSITIVE_P(x)) { + if (LLONG_MAX < num) + rb_raise(rb_eRangeError, "bignum too big to convert into `long long'"); + return num; + } + else { + if (num <= LLONG_MAX) + return -(LONG_LONG)num; + if (num == 1+(unsigned LONG_LONG)(-(LLONG_MIN+1))) + return LLONG_MIN; + rb_raise(rb_eRangeError, "bignum too big to convert into `long long'"); } - if (!RBIGNUM_SIGN(x)) return -(LONG_LONG)num; - return num; } #endif /* HAVE_LONG_LONG */ |