[ruby/bigdecimal] Let BigDecimal#quo accept precision
Fix GH-214. https://github.com/ruby/bigdecimal/commit/13e0e93f37
This commit is contained in:
parent
0b8638cd74
commit
79712fc083
@ -115,6 +115,8 @@ static ID id_half;
|
||||
*/
|
||||
static unsigned short VpGetException(void);
|
||||
static void VpSetException(unsigned short f);
|
||||
static void VpCheckException(Real *p, bool always);
|
||||
static VALUE VpCheckGetValue(Real *p);
|
||||
static void VpInternalRound(Real *c, size_t ixDigit, DECDIG vPrev, DECDIG v);
|
||||
static int VpLimitRound(Real *c, size_t ixDigit);
|
||||
static Real *VpCopy(Real *pv, Real const* const x);
|
||||
@ -165,27 +167,6 @@ is_kind_of_BigDecimal(VALUE const v)
|
||||
return rb_typeddata_is_kind_of(v, &BigDecimal_data_type);
|
||||
}
|
||||
|
||||
static void
|
||||
VpCheckException(Real *p, bool always)
|
||||
{
|
||||
if (VpIsNaN(p)) {
|
||||
VpException(VP_EXCEPTION_NaN, "Computation results in 'NaN' (Not a Number)", always);
|
||||
}
|
||||
else if (VpIsPosInf(p)) {
|
||||
VpException(VP_EXCEPTION_INFINITY, "Computation results in 'Infinity'", always);
|
||||
}
|
||||
else if (VpIsNegInf(p)) {
|
||||
VpException(VP_EXCEPTION_INFINITY, "Computation results in '-Infinity'", always);
|
||||
}
|
||||
}
|
||||
|
||||
static VALUE
|
||||
VpCheckGetValue(Real *p)
|
||||
{
|
||||
VpCheckException(p, false);
|
||||
return p->obj;
|
||||
}
|
||||
|
||||
NORETURN(static void cannot_be_coerced_into_BigDecimal(VALUE, VALUE));
|
||||
|
||||
static void
|
||||
@ -1656,12 +1637,15 @@ BigDecimal_divide(VALUE self, VALUE r, Real **c, Real **res, Real **div)
|
||||
}
|
||||
|
||||
/* call-seq:
|
||||
* a / b -> bigdecimal
|
||||
* quo(value) -> bigdecimal
|
||||
* a / b -> bigdecimal
|
||||
*
|
||||
* Divide by the specified value.
|
||||
*
|
||||
* The result precision will be the precision of the larger operand,
|
||||
* but its minimum is 2*Float::DIG.
|
||||
*
|
||||
* See BigDecimal#div.
|
||||
* See BigDecimal#quo.
|
||||
*/
|
||||
static VALUE
|
||||
BigDecimal_div(VALUE self, VALUE r)
|
||||
@ -1683,6 +1667,45 @@ BigDecimal_div(VALUE self, VALUE r)
|
||||
return VpCheckGetValue(c);
|
||||
}
|
||||
|
||||
static VALUE BigDecimal_round(int argc, VALUE *argv, VALUE self);
|
||||
|
||||
/* call-seq:
|
||||
* quo(value) -> bigdecimal
|
||||
* quo(value, digits) -> bigdecimal
|
||||
*
|
||||
* Divide by the specified value.
|
||||
*
|
||||
* digits:: If specified and less than the number of significant digits of
|
||||
* the result, the result is rounded to the given number of digits,
|
||||
* according to the rounding mode indicated by BigDecimal.mode.
|
||||
*
|
||||
* If digits is 0 or omitted, the result is the same as for the
|
||||
* / operator.
|
||||
*
|
||||
* See BigDecimal#/.
|
||||
* See BigDecimal#div.
|
||||
*/
|
||||
static VALUE
|
||||
BigDecimal_quo(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
VALUE value, digits, result;
|
||||
SIGNED_VALUE n = -1;
|
||||
|
||||
argc = rb_scan_args(argc, argv, "11", &value, &digits);
|
||||
if (argc > 1) {
|
||||
n = GetPrecisionInt(digits);
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
result = BigDecimal_div2(self, value, digits);
|
||||
}
|
||||
else {
|
||||
result = BigDecimal_div(self, value);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* %: mod = a%b = a - (a.to_f/b).floor * b
|
||||
* div = (a.to_f/b).floor
|
||||
@ -1964,6 +1987,7 @@ BigDecimal_div2(VALUE self, VALUE b, VALUE n)
|
||||
* Document-method: BigDecimal#div
|
||||
*
|
||||
* call-seq:
|
||||
* div(value) -> integer
|
||||
* div(value, digits) -> bigdecimal or integer
|
||||
*
|
||||
* Divide by the specified value.
|
||||
@ -1978,6 +2002,9 @@ BigDecimal_div2(VALUE self, VALUE b, VALUE n)
|
||||
* If digits is not specified, the result is an integer,
|
||||
* by analogy with Float#div; see also BigDecimal#divmod.
|
||||
*
|
||||
* See BigDecimal#/.
|
||||
* See BigDecimal#quo.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* a = BigDecimal("4")
|
||||
@ -4272,7 +4299,7 @@ Init_bigdecimal(void)
|
||||
rb_define_method(rb_cBigDecimal, "-@", BigDecimal_neg, 0);
|
||||
rb_define_method(rb_cBigDecimal, "*", BigDecimal_mult, 1);
|
||||
rb_define_method(rb_cBigDecimal, "/", BigDecimal_div, 1);
|
||||
rb_define_method(rb_cBigDecimal, "quo", BigDecimal_div, 1);
|
||||
rb_define_method(rb_cBigDecimal, "quo", BigDecimal_quo, -1);
|
||||
rb_define_method(rb_cBigDecimal, "%", BigDecimal_mod, 1);
|
||||
rb_define_method(rb_cBigDecimal, "modulo", BigDecimal_mod, 1);
|
||||
rb_define_method(rb_cBigDecimal, "remainder", BigDecimal_remainder, 1);
|
||||
@ -4446,6 +4473,27 @@ VpSetException(unsigned short f)
|
||||
bigdecimal_set_thread_local_exception_mode(f);
|
||||
}
|
||||
|
||||
static void
|
||||
VpCheckException(Real *p, bool always)
|
||||
{
|
||||
if (VpIsNaN(p)) {
|
||||
VpException(VP_EXCEPTION_NaN, "Computation results in 'NaN' (Not a Number)", always);
|
||||
}
|
||||
else if (VpIsPosInf(p)) {
|
||||
VpException(VP_EXCEPTION_INFINITY, "Computation results in 'Infinity'", always);
|
||||
}
|
||||
else if (VpIsNegInf(p)) {
|
||||
VpException(VP_EXCEPTION_INFINITY, "Computation results in '-Infinity'", always);
|
||||
}
|
||||
}
|
||||
|
||||
static VALUE
|
||||
VpCheckGetValue(Real *p)
|
||||
{
|
||||
VpCheckException(p, false);
|
||||
return p->obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* Precision limit.
|
||||
*/
|
||||
|
@ -1101,6 +1101,30 @@ class TestBigDecimal < Test::Unit::TestCase
|
||||
x.div(y, 100))
|
||||
end
|
||||
|
||||
def test_quo_without_prec
|
||||
x = BigDecimal(5)
|
||||
y = BigDecimal(229)
|
||||
assert_equal(BigDecimal("0.021834061135371179039301310043668122"), x.quo(y))
|
||||
end
|
||||
|
||||
def test_quo_with_prec
|
||||
begin
|
||||
saved_mode = BigDecimal.mode(BigDecimal::ROUND_MODE)
|
||||
BigDecimal.mode(BigDecimal::ROUND_MODE, :half_up)
|
||||
|
||||
x = BigDecimal(5)
|
||||
y = BigDecimal(229)
|
||||
assert_equal(BigDecimal("0.021834061135371179039301310043668122"), x.quo(y, 0))
|
||||
assert_equal(BigDecimal("0.022"), x.quo(y, 2))
|
||||
assert_equal(BigDecimal("0.0218"), x.quo(y, 3))
|
||||
assert_equal(BigDecimal("0.0218341"), x.quo(y, 6))
|
||||
assert_equal(BigDecimal("0.02183406114"), x.quo(y, 10))
|
||||
assert_equal(BigDecimal("0.021834061135371179039301310043668122270742358078603"), x.quo(y, 50))
|
||||
ensure
|
||||
BigDecimal.mode(BigDecimal::ROUND_MODE, saved_mode)
|
||||
end
|
||||
end
|
||||
|
||||
def test_abs_bigdecimal
|
||||
x = BigDecimal((2**100).to_s)
|
||||
assert_equal(1267650600228229401496703205376, x.abs)
|
||||
|
Loading…
x
Reference in New Issue
Block a user