From a86c147579745859ea064ec22b2901a7ac7e4abf Mon Sep 17 00:00:00 2001 From: Kenta Murata Date: Tue, 15 Dec 2020 15:17:15 +0900 Subject: [PATCH] Import bigdecimal 2.0.2 (#3905) * remove duplicated include * Make BigDecimal#round with argument < 1 return Integer Fixes [Bug #12780] * Use a higher default precision for BigDecimal#power and #** When a fractional power is given, increase the precision if the precision isn't specified via power's second argument: Float: increase by 15 (rough number of decimal precision in float) BigDecimal: increase by adding similar precision modifier as done to calculate the base precision. Rational: double the precision, since a BigDecimal is created, but the created BigDecimal uses the same precision. Increasing the precision for these power calculations has the obvious tradeoff of making the calculations slower. Fixes Ruby Bug #17264 * Use DBLE_FIG for a Float value * Version 2.0.1 Co-authored-by: pavel Co-authored-by: Jeremy Evans --- ext/bigdecimal/bigdecimal.c | 22 +++++++++++++++++----- ext/bigdecimal/bigdecimal.gemspec | 2 +- test/bigdecimal/test_bigdecimal.rb | 12 +++++++++++- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c index adce9de5a8..bc7fcc6ee8 100644 --- a/ext/bigdecimal/bigdecimal.c +++ b/ext/bigdecimal/bigdecimal.c @@ -25,7 +25,6 @@ #include #include #include -#include "math.h" #ifdef HAVE_IEEEFP_H #include @@ -1792,10 +1791,10 @@ BigDecimal_fix(VALUE self) * more than that many digits. * * If n is specified and negative, at least that many digits to the left of the - * decimal point will be 0 in the result. + * decimal point will be 0 in the result, and return value will be an Integer. * * BigDecimal('3.14159').round(3) #=> 3.142 - * BigDecimal('13345.234').round(-2) #=> 13300.0 + * BigDecimal('13345.234').round(-2) #=> 13300 * * The value of the optional mode argument can be used to determine how * rounding is performed; see BigDecimal.mode. @@ -1808,6 +1807,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self) int iLoc = 0; VALUE vLoc; VALUE vRound; + int round_to_int = 0; size_t mx, pl; unsigned short sw = VpGetRoundMode(); @@ -1815,6 +1815,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self) switch (rb_scan_args(argc, argv, "02", &vLoc, &vRound)) { case 0: iLoc = 0; + round_to_int = 1; break; case 1: if (RB_TYPE_P(vLoc, T_HASH)) { @@ -1822,6 +1823,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self) } else { iLoc = NUM2INT(vLoc); + if (iLoc < 1) round_to_int = 1; } break; case 2: @@ -1843,7 +1845,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self) GUARD_OBJ(c, VpCreateRbObject(mx, "0")); VpSetPrecLimit(pl); VpActiveRound(c, a, sw, iLoc); - if (argc == 0) { + if (round_to_int) { return BigDecimal_to_i(ToValue(c)); } return ToValue(c); @@ -2363,7 +2365,10 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self) } goto retry; } - exp = GetVpValueWithPrec(vexp, DBL_DIG+1, 1); + if (NIL_P(prec)) { + n += DBLE_FIG; + } + exp = GetVpValueWithPrec(vexp, DBLE_FIG, 1); break; case T_RATIONAL: @@ -2378,6 +2383,9 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self) goto retry; } exp = GetVpValueWithPrec(vexp, n, 1); + if (NIL_P(prec)) { + n += n; + } break; case T_DATA: @@ -2388,6 +2396,10 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self) vexp = BigDecimal_to_i(vexp); goto retry; } + if (NIL_P(prec)) { + GUARD_OBJ(y, GetVpValue(vexp, 1)); + n += y->Prec*VpBaseFig(); + } exp = DATA_PTR(vexp); break; } diff --git a/ext/bigdecimal/bigdecimal.gemspec b/ext/bigdecimal/bigdecimal.gemspec index 5cf0726e1e..980deb07b4 100644 --- a/ext/bigdecimal/bigdecimal.gemspec +++ b/ext/bigdecimal/bigdecimal.gemspec @@ -1,6 +1,6 @@ # coding: utf-8 -bigdecimal_version = '2.0.1' +bigdecimal_version = '2.0.2' Gem::Specification.new do |s| s.name = "bigdecimal" diff --git a/test/bigdecimal/test_bigdecimal.rb b/test/bigdecimal/test_bigdecimal.rb index 11174adaba..c8e70acfd0 100644 --- a/test/bigdecimal/test_bigdecimal.rb +++ b/test/bigdecimal/test_bigdecimal.rb @@ -1104,6 +1104,11 @@ class TestBigDecimal < Test::Unit::TestCase assert_equal(-1, x.round(0, BigDecimal::ROUND_HALF_DOWN), bug3803) assert_equal(-1, x.round(0, BigDecimal::ROUND_HALF_EVEN), bug3803) end + + assert_instance_of(Integer, x.round) + assert_instance_of(Integer, x.round(0)) + assert_instance_of(Integer, x.round(-1)) + assert_instance_of(BigDecimal, x.round(1)) end def test_round_half_even @@ -1456,8 +1461,13 @@ class TestBigDecimal < Test::Unit::TestCase def test_power_without_prec pi = BigDecimal("3.14159265358979323846264338327950288419716939937511") e = BigDecimal("2.71828182845904523536028747135266249775724709369996") - pow = BigDecimal("22.4591577183610454734271522045437350275893151339967843873233068") + pow = BigDecimal("0.2245915771836104547342715220454373502758931513399678438732330680117143493477164265678321738086407229773690574073268002736527e2") assert_equal(pow, pi.power(e)) + + n = BigDecimal("2222") + assert_equal(BigDecimal("0.5171353084572525892492416e12"), (n ** 3.5)) + assert_equal(BigDecimal("0.517135308457252592e12"), (n ** 3.5r)) + assert_equal(BigDecimal("0.517135308457252589249241582e12"), (n ** BigDecimal("3.5",15))) end def test_power_with_prec