summaryrefslogtreecommitdiff
path: root/ext/bigdecimal
diff options
context:
space:
mode:
authorKenta Murata <mrkn@mrkn.jp>2021-12-09 22:24:12 +0900
committerKenta Murata <mrkn@mrkn.jp>2021-12-24 02:29:00 +0900
commit79712fc083f483b3ef174f6ab457f8b63b87c43e (patch)
tree77b4e2a04e30926afb829b532049b3c6030a966b /ext/bigdecimal
parent0b8638cd7439570bc553ed1684a9f59da7d9c103 (diff)
downloadruby-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.c96
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.
*/