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 <pavel.rosicky@easy.cz>
Co-authored-by: Jeremy Evans <code@jeremyevans.net>
This commit is contained in:
Kenta Murata 2020-12-15 15:17:15 +09:00 committed by GitHub
parent 9d85ed6cbb
commit a86c147579
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
Notes: git 2020-12-15 15:17:40 +09:00
Merged-By: mrkn <mrkn@ruby-lang.org>
3 changed files with 29 additions and 7 deletions

View File

@ -25,7 +25,6 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <math.h> #include <math.h>
#include "math.h"
#ifdef HAVE_IEEEFP_H #ifdef HAVE_IEEEFP_H
#include <ieeefp.h> #include <ieeefp.h>
@ -1792,10 +1791,10 @@ BigDecimal_fix(VALUE self)
* more than that many digits. * more than that many digits.
* *
* If n is specified and negative, at least that many digits to the left of the * 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('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 * The value of the optional mode argument can be used to determine how
* rounding is performed; see BigDecimal.mode. * rounding is performed; see BigDecimal.mode.
@ -1808,6 +1807,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
int iLoc = 0; int iLoc = 0;
VALUE vLoc; VALUE vLoc;
VALUE vRound; VALUE vRound;
int round_to_int = 0;
size_t mx, pl; size_t mx, pl;
unsigned short sw = VpGetRoundMode(); 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)) { switch (rb_scan_args(argc, argv, "02", &vLoc, &vRound)) {
case 0: case 0:
iLoc = 0; iLoc = 0;
round_to_int = 1;
break; break;
case 1: case 1:
if (RB_TYPE_P(vLoc, T_HASH)) { if (RB_TYPE_P(vLoc, T_HASH)) {
@ -1822,6 +1823,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
} }
else { else {
iLoc = NUM2INT(vLoc); iLoc = NUM2INT(vLoc);
if (iLoc < 1) round_to_int = 1;
} }
break; break;
case 2: case 2:
@ -1843,7 +1845,7 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self)
GUARD_OBJ(c, VpCreateRbObject(mx, "0")); GUARD_OBJ(c, VpCreateRbObject(mx, "0"));
VpSetPrecLimit(pl); VpSetPrecLimit(pl);
VpActiveRound(c, a, sw, iLoc); VpActiveRound(c, a, sw, iLoc);
if (argc == 0) { if (round_to_int) {
return BigDecimal_to_i(ToValue(c)); return BigDecimal_to_i(ToValue(c));
} }
return ToValue(c); return ToValue(c);
@ -2363,7 +2365,10 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self)
} }
goto retry; goto retry;
} }
exp = GetVpValueWithPrec(vexp, DBL_DIG+1, 1); if (NIL_P(prec)) {
n += DBLE_FIG;
}
exp = GetVpValueWithPrec(vexp, DBLE_FIG, 1);
break; break;
case T_RATIONAL: case T_RATIONAL:
@ -2378,6 +2383,9 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self)
goto retry; goto retry;
} }
exp = GetVpValueWithPrec(vexp, n, 1); exp = GetVpValueWithPrec(vexp, n, 1);
if (NIL_P(prec)) {
n += n;
}
break; break;
case T_DATA: case T_DATA:
@ -2388,6 +2396,10 @@ BigDecimal_power(int argc, VALUE*argv, VALUE self)
vexp = BigDecimal_to_i(vexp); vexp = BigDecimal_to_i(vexp);
goto retry; goto retry;
} }
if (NIL_P(prec)) {
GUARD_OBJ(y, GetVpValue(vexp, 1));
n += y->Prec*VpBaseFig();
}
exp = DATA_PTR(vexp); exp = DATA_PTR(vexp);
break; break;
} }

View File

@ -1,6 +1,6 @@
# coding: utf-8 # coding: utf-8
bigdecimal_version = '2.0.1' bigdecimal_version = '2.0.2'
Gem::Specification.new do |s| Gem::Specification.new do |s|
s.name = "bigdecimal" s.name = "bigdecimal"

View File

@ -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_DOWN), bug3803)
assert_equal(-1, x.round(0, BigDecimal::ROUND_HALF_EVEN), bug3803) assert_equal(-1, x.round(0, BigDecimal::ROUND_HALF_EVEN), bug3803)
end 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 end
def test_round_half_even def test_round_half_even
@ -1456,8 +1461,13 @@ class TestBigDecimal < Test::Unit::TestCase
def test_power_without_prec def test_power_without_prec
pi = BigDecimal("3.14159265358979323846264338327950288419716939937511") pi = BigDecimal("3.14159265358979323846264338327950288419716939937511")
e = BigDecimal("2.71828182845904523536028747135266249775724709369996") e = BigDecimal("2.71828182845904523536028747135266249775724709369996")
pow = BigDecimal("22.4591577183610454734271522045437350275893151339967843873233068") pow = BigDecimal("0.2245915771836104547342715220454373502758931513399678438732330680117143493477164265678321738086407229773690574073268002736527e2")
assert_equal(pow, pi.power(e)) 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 end
def test_power_with_prec def test_power_with_prec