summaryrefslogtreecommitdiffhomepage
path: root/mrbgems
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2021-03-24 19:01:58 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2021-03-24 19:01:58 +0900
commit9d058342a5ab370698616069f760789a47cbbfd0 (patch)
tree6e270f6fed159330cce5dcd1255f833f90f5e6d6 /mrbgems
parent7a35b64251b8a8b97db9e35df5eb6a2b4aa607e8 (diff)
downloadmruby-9d058342a5ab370698616069f760789a47cbbfd0.tar.gz
mruby-9d058342a5ab370698616069f760789a47cbbfd0.zip
rational.c: implement `Rational#-` in C.
Diffstat (limited to 'mrbgems')
-rw-r--r--mrbgems/mruby-rational/mrblib/rational.rb10
-rw-r--r--mrbgems/mruby-rational/src/rational.c54
2 files changed, 52 insertions, 12 deletions
diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb
index 090928d6d..8b851077e 100644
--- a/mrbgems/mruby-rational/mrblib/rational.rb
+++ b/mrbgems/mruby-rational/mrblib/rational.rb
@@ -17,16 +17,6 @@ class Rational < Numeric
end
end
- def -(rhs)
- if rhs.is_a? Rational
- Rational(numerator * rhs.denominator - rhs.numerator * denominator, denominator * rhs.denominator)
- elsif rhs.is_a? Integer
- Rational(numerator - rhs * denominator, denominator)
- elsif rhs.is_a? Numeric
- (numerator - rhs * denominator) / denominator
- end
- end
-
def /(rhs)
if rhs.is_a? Rational
Rational(numerator * rhs.denominator, denominator * rhs.numerator)
diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c
index 1b2cfcbec..c11a93576 100644
--- a/mrbgems/mruby-rational/src/rational.c
+++ b/mrbgems/mruby-rational/src/rational.c
@@ -457,8 +457,57 @@ rational_add(mrb_state *mrb, mrb_value x)
}
}
-mrb_int mrb_num_div_int(mrb_state*, mrb_int, mrb_int);
-mrb_value mrb_complex_new(mrb_state*, mrb_float, mrb_float);
+#ifndef MRB_NO_FLOAT
+mrb_value mrb_complex_new(mrb_state *, mrb_float, mrb_float);
+#endif
+
+static mrb_value
+rational_sub(mrb_state *mrb, mrb_value x)
+{
+ struct mrb_rational *p1 = rational_ptr(mrb, x);
+ mrb_value y = mrb_get_arg1(mrb);
+
+ switch (mrb_type(y)) {
+ case MRB_TT_INTEGER:
+ {
+ mrb_int z = mrb_integer(y);
+ if (mrb_int_mul_overflow(z, p1->denominator, &z)) rat_overflow(mrb);
+ if (mrb_int_sub_overflow(p1->numerator, z, &z)) rat_overflow(mrb);
+ return rational_new_i(mrb, z, p1->denominator);
+ }
+ case MRB_TT_RATIONAL:
+ {
+ struct mrb_rational *p2 = rational_ptr(mrb, y);
+ mrb_int a, b;
+
+ if (mrb_int_mul_overflow(p1->numerator, p2->denominator, &a)) rat_overflow(mrb);
+ if (mrb_int_mul_overflow(p2->numerator, p1->denominator, &b)) rat_overflow(mrb);
+ if (mrb_int_sub_overflow(a, b, &a)) rat_overflow(mrb);
+ if (mrb_int_mul_overflow(p1->denominator, p2->denominator, &b)) rat_overflow(mrb);
+ return rational_new_i(mrb, a, b);
+ }
+
+#if defined(MRB_USE_COMPLEX)
+ case MRB_TT_COMPLEX:
+ x = mrb_complex_new(mrb, rat_to_flo(p1), 0);
+ return mrb_funcall_id(mrb, x, MRB_OPSYM(sub), 1, y);
+#endif
+
+#ifndef MRB_NO_FLOAT
+ case MRB_TT_FLOAT:
+ default:
+ {
+ mrb_float z = p1->numerator - mrb_to_flo(mrb, y) * p1->denominator;
+ return mrb_float_value(mrb, mrb_num_div_flo(mrb, z, (mrb_float)p1->denominator));
+ }
+#else
+ default:
+ mrb_raise(mrb, E_TYPE_ERROR, "non integer subtraction");
+#endif
+ }
+}
+
+mrb_int mrb_num_div_int(mrb_state *, mrb_int, mrb_int);
/* 15.2.8.3.4 */
/*
@@ -544,6 +593,7 @@ void mrb_mruby_rational_gem_init(mrb_state *mrb)
mrb_define_method(mrb, rat, "==", rational_eq, MRB_ARGS_REQ(1));
mrb_define_method(mrb, rat, "-@", rational_minus, MRB_ARGS_NONE());
mrb_define_method(mrb, rat, "+", rational_add, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, rat, "-", rational_sub, MRB_ARGS_REQ(1));
mrb_define_method(mrb, mrb->integer_class, "to_r", fix_to_r, MRB_ARGS_NONE());
mrb_define_method(mrb, mrb->integer_class, "/", int_div, MRB_ARGS_REQ(1)); /* overrride */
mrb_define_method(mrb, mrb->integer_class, "quo", int_quo, MRB_ARGS_REQ(1)); /* overrride */