[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 unsigned short VpGetException(void);
|
||||||
static void VpSetException(unsigned short f);
|
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 void VpInternalRound(Real *c, size_t ixDigit, DECDIG vPrev, DECDIG v);
|
||||||
static int VpLimitRound(Real *c, size_t ixDigit);
|
static int VpLimitRound(Real *c, size_t ixDigit);
|
||||||
static Real *VpCopy(Real *pv, Real const* const x);
|
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);
|
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));
|
NORETURN(static void cannot_be_coerced_into_BigDecimal(VALUE, VALUE));
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1656,12 +1637,15 @@ BigDecimal_divide(VALUE self, VALUE r, Real **c, Real **res, Real **div)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* call-seq:
|
/* call-seq:
|
||||||
* a / b -> bigdecimal
|
* a / b -> bigdecimal
|
||||||
* quo(value) -> bigdecimal
|
|
||||||
*
|
*
|
||||||
* Divide by the specified value.
|
* 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#div.
|
||||||
|
* See BigDecimal#quo.
|
||||||
*/
|
*/
|
||||||
static VALUE
|
static VALUE
|
||||||
BigDecimal_div(VALUE self, VALUE r)
|
BigDecimal_div(VALUE self, VALUE r)
|
||||||
@ -1683,6 +1667,45 @@ BigDecimal_div(VALUE self, VALUE r)
|
|||||||
return VpCheckGetValue(c);
|
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
|
* %: mod = a%b = a - (a.to_f/b).floor * b
|
||||||
* div = (a.to_f/b).floor
|
* div = (a.to_f/b).floor
|
||||||
@ -1964,6 +1987,7 @@ BigDecimal_div2(VALUE self, VALUE b, VALUE n)
|
|||||||
* Document-method: BigDecimal#div
|
* Document-method: BigDecimal#div
|
||||||
*
|
*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
|
* div(value) -> integer
|
||||||
* div(value, digits) -> bigdecimal or integer
|
* div(value, digits) -> bigdecimal or integer
|
||||||
*
|
*
|
||||||
* Divide by the specified value.
|
* 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,
|
* If digits is not specified, the result is an integer,
|
||||||
* by analogy with Float#div; see also BigDecimal#divmod.
|
* by analogy with Float#div; see also BigDecimal#divmod.
|
||||||
*
|
*
|
||||||
|
* See BigDecimal#/.
|
||||||
|
* See BigDecimal#quo.
|
||||||
|
*
|
||||||
* Examples:
|
* Examples:
|
||||||
*
|
*
|
||||||
* a = BigDecimal("4")
|
* a = BigDecimal("4")
|
||||||
@ -4272,7 +4299,7 @@ Init_bigdecimal(void)
|
|||||||
rb_define_method(rb_cBigDecimal, "-@", BigDecimal_neg, 0);
|
rb_define_method(rb_cBigDecimal, "-@", BigDecimal_neg, 0);
|
||||||
rb_define_method(rb_cBigDecimal, "*", BigDecimal_mult, 1);
|
rb_define_method(rb_cBigDecimal, "*", BigDecimal_mult, 1);
|
||||||
rb_define_method(rb_cBigDecimal, "/", BigDecimal_div, 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, "%", BigDecimal_mod, 1);
|
||||||
rb_define_method(rb_cBigDecimal, "modulo", BigDecimal_mod, 1);
|
rb_define_method(rb_cBigDecimal, "modulo", BigDecimal_mod, 1);
|
||||||
rb_define_method(rb_cBigDecimal, "remainder", BigDecimal_remainder, 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);
|
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.
|
* Precision limit.
|
||||||
*/
|
*/
|
||||||
|
@ -1101,6 +1101,30 @@ class TestBigDecimal < Test::Unit::TestCase
|
|||||||
x.div(y, 100))
|
x.div(y, 100))
|
||||||
end
|
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
|
def test_abs_bigdecimal
|
||||||
x = BigDecimal((2**100).to_s)
|
x = BigDecimal((2**100).to_s)
|
||||||
assert_equal(1267650600228229401496703205376, x.abs)
|
assert_equal(1267650600228229401496703205376, x.abs)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user