summaryrefslogtreecommitdiffhomepage
path: root/mrbgems
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2021-03-18 16:27:35 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2021-03-19 10:37:10 +0900
commit08f9d5bab5092fe1193dd100765079e3e4d746b9 (patch)
tree627588dd204f5a7c24ea79ab17076f3eeab818eb /mrbgems
parenteb070303080b24458d3740424aa7aa8a45fa49eb (diff)
downloadmruby-08f9d5bab5092fe1193dd100765079e3e4d746b9.tar.gz
mruby-08f9d5bab5092fe1193dd100765079e3e4d746b9.zip
rational.c: overhaul rational operators.
- define `MRB_TT_RATIONAL` - change object structure (`struct RRational`) - add memory management for `MRB_TT_RATIONAL` - avoid operator overloading as much as possible - implement division overloading in C - as a result, performance improved a lot
Diffstat (limited to 'mrbgems')
-rw-r--r--mrbgems/mruby-rational/mrbgem.rake1
-rw-r--r--mrbgems/mruby-rational/mrblib/rational.rb36
-rw-r--r--mrbgems/mruby-rational/src/rational.c195
3 files changed, 155 insertions, 77 deletions
diff --git a/mrbgems/mruby-rational/mrbgem.rake b/mrbgems/mruby-rational/mrbgem.rake
index 4b540dec4..358fb838a 100644
--- a/mrbgems/mruby-rational/mrbgem.rake
+++ b/mrbgems/mruby-rational/mrbgem.rake
@@ -2,4 +2,5 @@ MRuby::Gem::Specification.new('mruby-rational') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
spec.summary = 'Rational class'
+ spec.build.cc.defines << "MRB_USE_RATIONAL"
end
diff --git a/mrbgems/mruby-rational/mrblib/rational.rb b/mrbgems/mruby-rational/mrblib/rational.rb
index aaafc9899..a9edeaad4 100644
--- a/mrbgems/mruby-rational/mrblib/rational.rb
+++ b/mrbgems/mruby-rational/mrblib/rational.rb
@@ -64,17 +64,6 @@ class Rational < Numeric
nil
end
end
-
- def ==(rhs)
- return true if self.equal?(rhs)
- case rhs
- when Integer, Float
- return numerator == rhs if denominator == 1
- when Rational
- return numerator * rhs.denominator == denominator * rhs.numerator
- end
- rhs == self
- end
end
class Numeric
@@ -82,28 +71,3 @@ class Numeric
Rational(self, 1)
end
end
-
-module Kernel
- [:+, :-, :*, :/, :<=>, :==, :<, :<=, :>, :>=].each do |op|
- original_operator_name = :"__original_operator_#{op}_rational"
- Integer.instance_eval do
- alias_method original_operator_name, op
- define_method op do |rhs|
- if rhs.is_a? Rational
- Rational(self).__send__(op, rhs)
- else
- __send__(original_operator_name, rhs)
- end
- end
- end
- Float.instance_eval do
- alias_method original_operator_name, op
- define_method op do |rhs|
- if rhs.is_a? Rational
- rhs = rhs.to_f
- end
- __send__(original_operator_name, rhs)
- end
- end if Object.const_defined?(:Float)
- end
-end
diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c
index 618ffa805..abb200e79 100644
--- a/mrbgems/mruby-rational/src/rational.c
+++ b/mrbgems/mruby-rational/src/rational.c
@@ -9,53 +9,45 @@ struct mrb_rational {
mrb_int denominator;
};
-#if MRB_INT_MAX <= INTPTR_MAX
-
-#define RATIONAL_USE_ISTRUCT
-/* use TT_ISTRUCT */
#include <mruby/istruct.h>
-#define rational_ptr(mrb, v) (struct mrb_rational*)mrb_istruct_ptr(v)
+#if defined(MRB_INT64) && defined(MRB_32BIT)
+struct RRational {
+ MRB_OBJECT_HEADER;
+ struct mrb_rational *p;
+};
-static struct RBasic*
-rational_alloc(mrb_state *mrb, struct RClass *c, struct mrb_rational **p)
+static struct mrb_rational*
+rational_ptr(mrb_state *mrb, mrb_value v)
{
- struct RIStruct *s;
-
- s = (struct RIStruct*)mrb_obj_alloc(mrb, MRB_TT_ISTRUCT, c);
- *p = (struct mrb_rational*)s->inline_data;
+ struct RRational *r = (struct RRational*)mrb_obj_ptr(v);
- return (struct RBasic*)s;
+ if (!r->p) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized rational");
+ }
+ return r->p;
}
-
#else
-/* use TT_DATA */
-#include <mruby/data.h>
-
-static const struct mrb_data_type mrb_rational_type = {"Rational", mrb_free};
+#define RATIONAL_INLINE
+struct RRational {
+ MRB_OBJECT_HEADER;
+ struct mrb_rational r;
+};
+#define rational_ptr(mrb, v) (&((struct RRational*)mrb_obj_ptr(v))->r)
+#endif
static struct RBasic*
rational_alloc(mrb_state *mrb, struct RClass *c, struct mrb_rational **p)
{
- struct RData *d;
-
- Data_Make_Struct(mrb, c, struct mrb_rational, &mrb_rational_type, *p, d);
-
- return (struct RBasic*)d;
-}
-
-static struct mrb_rational*
-rational_ptr(mrb_state *mrb, mrb_value v)
-{
- struct mrb_rational *p;
-
- p = DATA_GET_PTR(mrb, v, &mrb_rational_type, struct mrb_rational);
- if (!p) {
- mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized rational");
- }
- return p;
-}
+ struct RRational *s;
+ s = (struct RRational*)mrb_obj_alloc(mrb, MRB_TT_RATIONAL, c);
+#ifdef RATIONAL_INLINE
+ *p = &s->r;
+#else
+ *p = s->p = (struct mrb_rational*)mrb_malloc(mrb, sizeof(struct mrb_rational));
#endif
+ return (struct RBasic*)s;
+}
static mrb_value
rational_numerator(mrb_state *mrb, mrb_value self)
@@ -356,17 +348,134 @@ rational_m(mrb_state *mrb, mrb_value self)
#endif
}
+mrb_bool
+mrb_rational_eq(mrb_state *mrb, mrb_value x, mrb_value y)
+{
+ struct mrb_rational *p1 = rational_ptr(mrb, x);
+
+ switch (mrb_type(y)) {
+ case MRB_TT_INTEGER:
+ if (p1->denominator != 1) return FALSE;
+ return p1->numerator == mrb_integer(y);
+#ifndef MRB_NO_FLOAT
+ case MRB_TT_FLOAT:
+ return ((double)p1->numerator/p1->denominator) == mrb_float(y);
+#endif
+ case MRB_TT_RATIONAL:
+ {
+ struct mrb_rational *p2 = rational_ptr(mrb, y);
+ mrb_int a, b;
+
+ if (p1->numerator == p2->numerator && p1->denominator == p2->denominator) {
+ return TRUE;
+ }
+ if (mrb_int_mul_overflow(p1->numerator, p2->denominator, &a) ||
+ mrb_int_mul_overflow(p2->numerator, p1->denominator, &b)) {
+#ifdef MRB_NO_FLOAT
+ rat_overflow(mrb);
+#else
+ return (double)p1->numerator*p2->denominator == (double)p2->numerator*p2->denominator;
+#endif
+ }
+ return a == b;
+ }
+#ifdef MRB_USE_COMPLEX
+ case MRB_TT_RATIONAL:
+ {
+ mrb_bool mrb_complex_eq(mrb_state *mrb, mrb_value, mrb_value);
+ return mrb_complex_eq(mrb, y, x);
+ }
+#endif
+ default:
+ return mrb_equal(mrb, y, x);
+ }
+}
+
+static mrb_value
+rational_eq(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y = mrb_get_arg1(mrb);
+ return mrb_bool_value(mrb_rational_eq(mrb, x, y));
+}
+
+static mrb_value
+rational_minus(mrb_state *mrb, mrb_value x)
+{
+ struct mrb_rational *p = rational_ptr(mrb, x);
+ return rational_new(mrb, -p->numerator, p->denominator);
+}
+
+mrb_int mrb_num_div_int(mrb_state *, mrb_int, mrb_int);
+
+/* 15.2.8.3.4 */
+/*
+ * redefine Integer#/
+ */
+static mrb_value
+int_div(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y = mrb_get_arg1(mrb);
+ mrb_int a = mrb_integer(x);
+
+ if (mrb_integer_p(y)) {
+ mrb_int div = mrb_num_div_int(mrb, a, mrb_integer(y));
+ return mrb_int_value(mrb, div);
+ }
+ switch (mrb_type(y)) {
+ case MRB_TT_RATIONAL:
+ x = rational_new(mrb, a, 1);
+ return mrb_funcall_id(mrb, x, MRB_OPSYM(div), 1, y);
+#if defined(MRB_USE_COMPLEX)
+ case MRB_TT_COMPLEX:
+ return mrb_funcall_id(mrb, x, MRB_OPSYM(div), 1, y);
+#endif
+ case MRB_TT_FLOAT:
+ default:
+#ifdef MRB_NO_FLOAT
+ mrb_raise(mrb, E_TYPE_ERROR, "non integer multiplication");
+#else
+ return mrb_float_value(mrb, (mrb_float)a * mrb_to_flo(mrb, y));
+#endif
+ }
+}
+
+/* 15.2.9.3.19(x) */
+/*
+ * redefine Integer#quo
+ */
+
+static mrb_value
+int_quo(mrb_state *mrb, mrb_value x)
+{
+ mrb_value y = mrb_get_arg1(mrb);
+ mrb_int a = mrb_integer(x);
+
+ if (mrb_integer_p(y)) {
+ return rational_new(mrb, a, mrb_integer(y));
+ }
+ switch (mrb_type(y)) {
+ case MRB_TT_RATIONAL:
+ x = rational_new(mrb, a, 1);
+ return mrb_funcall_id(mrb, x, MRB_OPSYM(div), 1, y);
+#if defined(MRB_USE_COMPLEX)
+ case MRB_TT_COMPLEX:
+ return mrb_funcall_id(mrb, x, MRB_OPSYM(div), 1, y);
+#endif
+ default:
+#ifdef MRB_NO_FLOAT
+ mrb_raise(mrb, E_TYPE_ERROR, "non integer multiplication");
+#else
+ return mrb_float_value(mrb, (mrb_float)a * mrb_to_flo(mrb, y));
+#endif
+ }
+}
+
void mrb_mruby_rational_gem_init(mrb_state *mrb)
{
struct RClass *rat;
rat = mrb_define_class_id(mrb, MRB_SYM(Rational), mrb_class_get_id(mrb, MRB_SYM(Numeric)));
-#ifdef RATIONAL_USE_ISTRUCT
- MRB_SET_INSTANCE_TT(rat, MRB_TT_ISTRUCT);
- mrb_assert(sizeof(struct mrb_rational) < ISTRUCT_DATA_SIZE);
-#else
- MRB_SET_INSTANCE_TT(rat, MRB_TT_DATA);
-#endif
+ MRB_SET_INSTANCE_TT(rat, MRB_TT_RATIONAL);
mrb_undef_class_method(mrb, rat, "new");
mrb_define_class_method(mrb, rat, "_new", rational_s_new, MRB_ARGS_REQ(2));
mrb_define_method(mrb, rat, "numerator", rational_numerator, MRB_ARGS_NONE());
@@ -377,7 +486,11 @@ void mrb_mruby_rational_gem_init(mrb_state *mrb)
mrb_define_method(mrb, rat, "to_i", rational_to_i, MRB_ARGS_NONE());
mrb_define_method(mrb, rat, "to_r", rational_to_r, MRB_ARGS_NONE());
mrb_define_method(mrb, rat, "negative?", rational_negative_p, MRB_ARGS_NONE());
+ 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, 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 */
mrb_define_method(mrb, mrb->kernel_module, "Rational", rational_m, MRB_ARGS_ARG(1,1));
}