diff --git a/bignum.c b/bignum.c index 8f351ee208..75651f9524 100644 --- a/bignum.c +++ b/bignum.c @@ -1645,6 +1645,12 @@ rb_big_sq_fast(VALUE x) return z; } +static inline size_t +max_size(size_t a, size_t b) +{ + return (a > b ? a : b); +} + /* balancing multiplication by slicing larger argument */ static void bary_mul_balance_with_mulfunc(BDIGIT *const zds, const size_t zn, @@ -1662,8 +1668,14 @@ bary_mul_balance_with_mulfunc(BDIGIT *const zds, const size_t zn, BDIGITS_ZERO(zds, xn); if (wn < xn) { - const size_t r = (yn % xn) ? (yn % xn) : xn; - if ((2 * xn + yn + r) > zn) { + /* The condition when a new buffer is needed: + * 1. (2(xn+r) > zn-(yn-r)) => (2xn+r > zn-yn), at the last + * iteration (or r == 0) + * 2. (2(xn+xn) > zn-(yn-r-xn)) => (3xn-r > zn-yn), at the + * previous iteration. + */ + const size_t r = yn % xn; + if (2*xn + yn + max_size(xn-r, r) > zn) { wn = xn; wds = ALLOCV_N(BDIGIT, work, wn); } diff --git a/test/ruby/test_bignum.rb b/test/ruby/test_bignum.rb index 53a2b20cc8..065a944853 100644 --- a/test/ruby/test_bignum.rb +++ b/test/ruby/test_bignum.rb @@ -203,6 +203,15 @@ class TestBignum < Test::Unit::TestCase assert_equal(00_02, '00_02'.to_i) end + def test_very_big_str_to_inum + assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") + begin; + digits = [["3", 700], ["0", 2700], ["1", 1], ["0", 26599]] + num = digits.inject("") {|s,(c,n)|s << c*n}.to_i + assert_equal digits.sum {|c,n|n}, num.to_s.size + end; + end + def test_to_s2 assert_raise(ArgumentError) { T31P.to_s(37) } assert_equal("9" * 32768, (10**32768-1).to_s)