summaryrefslogtreecommitdiff
path: root/rational.c
diff options
context:
space:
mode:
Diffstat (limited to 'rational.c')
-rw-r--r--rational.c38
1 files changed, 36 insertions, 2 deletions
diff --git a/rational.c b/rational.c
index f0e8d56cbf..8362075ab4 100644
--- a/rational.c
+++ b/rational.c
@@ -1250,7 +1250,7 @@ nurat_truncate(VALUE self)
}
static VALUE
-nurat_round(VALUE self)
+nurat_round_half_up(VALUE self)
{
VALUE num, den, neg;
@@ -1274,6 +1274,33 @@ nurat_round(VALUE self)
}
static VALUE
+nurat_round_half_even(VALUE self)
+{
+ VALUE num, den, neg, qr;
+
+ get_dat1(self);
+
+ num = dat->num;
+ den = dat->den;
+ neg = f_negative_p(num);
+
+ if (neg)
+ num = f_negate(num);
+
+ num = f_add(f_mul(num, TWO), den);
+ den = f_mul(den, TWO);
+ qr = rb_funcall(num, rb_intern("divmod"), 1, den);
+ num = RARRAY_AREF(qr, 0);
+ if (f_zero_p(RARRAY_AREF(qr, 1)))
+ num = rb_funcall(num, '&', 1, LONG2FIX(((int)~1)));
+
+ if (neg)
+ num = f_negate(num);
+
+ return num;
+}
+
+static VALUE
f_round_common(int argc, VALUE *argv, VALUE self, VALUE (*func)(VALUE))
{
VALUE n, b, s;
@@ -1403,7 +1430,14 @@ nurat_truncate_n(int argc, VALUE *argv, VALUE self)
static VALUE
nurat_round_n(int argc, VALUE *argv, VALUE self)
{
- return f_round_common(argc, argv, self, nurat_round);
+ VALUE opt;
+ enum ruby_num_rounding_mode mode = (
+ argc = rb_scan_args(argc, argv, "*:", NULL, &opt),
+ rb_num_get_rounding_option(opt));
+ VALUE (*round_func)(VALUE) =
+ ROUND_TO(mode,
+ nurat_round_half_up, nurat_round_half_even);
+ return f_round_common(argc, argv, self, round_func);
}
/*