ruby-changes:32075
From: mrkn <ko1@a...>
Date: Fri, 13 Dec 2013 02:02:36 +0900 (JST)
Subject: [ruby-changes:32075] mrkn:r44153 (trunk): * ext/bigdecimal/bigdecimal.c (VpSetPTR): fix for limitation of the resulting
mrkn 2013-12-13 02:02:27 +0900 (Fri, 13 Dec 2013) New Revision: 44153 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=44153 Log: * ext/bigdecimal/bigdecimal.c (VpSetPTR): fix for limitation of the resulting precision. * test/bigdecimal/test_bigdecimal.rb (test_limit): add tests for the above change. Modified files: trunk/ChangeLog trunk/ext/bigdecimal/bigdecimal.c trunk/test/bigdecimal/test_bigdecimal.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 44152) +++ ChangeLog (revision 44153) @@ -1,3 +1,11 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Wed Dec 13 02:00:00 2013 Kenta Murata <mrkn@m...> + + * ext/bigdecimal/bigdecimal.c (VpSetPTR): fix for limitation of the resulting + precision. + + * test/bigdecimal/test_bigdecimal.rb (test_limit): add tests for the above + change. + Wed Dec 13 01:56:00 2013 Kenta Murata <mrkn@m...> * ext/bigdecimal/bigdecimal.c (VpAddAbs): put out a conditional branch from Index: ext/bigdecimal/bigdecimal.c =================================================================== --- ext/bigdecimal/bigdecimal.c (revision 44152) +++ ext/bigdecimal/bigdecimal.c (revision 44153) @@ -4189,6 +4189,7 @@ VpAddAbs(Real *a, Real *b, Real *c) https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L4189 a_pos = ap; b_pos = bp; c_pos = cp; + if (word_shift == (size_t)-1L) return 0; /* Overflow */ if (b_pos == (size_t)-1L) goto Assign_a; @@ -4380,12 +4381,19 @@ static size_t https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L4381 VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos, BDIGIT *av, BDIGIT *bv) { size_t left_word, right_word, word_shift; + + size_t const round_limit = (VpGetPrecLimit() + BASE_FIG - 1) / BASE_FIG; + + assert(a->exponent >= b->expoennt); + c->frac[0] = 0; *av = *bv = 0; + word_shift = (a->exponent - b->exponent); left_word = b->Prec + word_shift; right_word = Max(a->Prec, left_word); left_word = c->MaxPrec - 1; /* -1 ... prepare for round up */ + /* * check if 'round' is needed. */ @@ -4408,7 +4416,9 @@ VpSetPTR(Real *a, Real *b, Real *c, size https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L4416 * a_pos = | */ *a_pos = left_word; - *av = a->frac[*a_pos]; /* av is 'A' shown in above. */ + if (*a_pos <= round_limit) { + *av = a->frac[*a_pos]; /* av is 'A' shown in above. */ + } } else { /* @@ -4427,7 +4437,9 @@ VpSetPTR(Real *a, Real *b, Real *c, size https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L4437 */ if (c->MaxPrec >= word_shift + 1) { *b_pos = c->MaxPrec - word_shift - 1; - *bv = b->frac[*b_pos]; + if (*b_pos + word_shift <= round_limit) { + *bv = b->frac[*b_pos]; + } } else { *b_pos = -1L; Index: test/bigdecimal/test_bigdecimal.rb =================================================================== --- test/bigdecimal/test_bigdecimal.rb (revision 44152) +++ test/bigdecimal/test_bigdecimal.rb (revision 44153) @@ -1151,6 +1151,25 @@ class TestBigDecimal < Test::Unit::TestC https://github.com/ruby/ruby/blob/trunk/test/bigdecimal/test_bigdecimal.rb#L1151 assert_equal(90, x ** 4) # OK? must it be 80? # 3 * 3 * 3 * 3 = 10 * 3 * 3 = 30 * 3 = 90 ??? assert_raise(ArgumentError) { BigDecimal.limit(-1) } + + bug7458 = '[ruby-core:50269] [#7458]' + one = BigDecimal('1') + epsilon = BigDecimal('0.7E-18') + BigDecimal.save_limit do + BigDecimal.limit(0) + assert_equal(BigDecimal("1.0000000000000000007"), one + epsilon, "limit(0) #{bug7458}") + + 1.upto(18) do |lim| + BigDecimal.limit(lim) + assert_equal(BigDecimal("1.0"), one + epsilon, "limit(#{lim}) #{bug7458}") + end + + BigDecimal.limit(19) + assert_equal(BigDecimal("1.000000000000000001"), one + epsilon, "limit(19) #{bug7458}") + + BigDecimal.limit(20) + assert_equal(BigDecimal("1.0000000000000000007"), one + epsilon, "limit(20) #{bug7458}") + end end def test_sign -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/