diff options
author | Kenta Murata <mrkn@mrkn.jp> | 2021-12-09 22:24:12 +0900 |
---|---|---|
committer | Kenta Murata <mrkn@mrkn.jp> | 2021-12-24 02:29:00 +0900 |
commit | 79712fc083f483b3ef174f6ab457f8b63b87c43e (patch) | |
tree | 77b4e2a04e30926afb829b532049b3c6030a966b /ext/bigdecimal | |
parent | 0b8638cd7439570bc553ed1684a9f59da7d9c103 (diff) | |
download | ruby-79712fc083f483b3ef174f6ab457f8b63b87c43e.tar.gz |
[ruby/bigdecimal] Let BigDecimal#quo accept precision
Fix GH-214.
https://github.com/ruby/bigdecimal/commit/13e0e93f37
Diffstat (limited to 'ext/bigdecimal')
-rw-r--r-- | ext/bigdecimal/bigdecimal.c | 96 |
1 files changed, 72 insertions, 24 deletions
diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c index c648616b7a..3be0ffec6d 100644 --- a/ext/bigdecimal/bigdecimal.c +++ b/ext/bigdecimal/bigdecimal.c @@ -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. */ |