diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2021-03-18 16:27:35 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2021-03-19 10:37:10 +0900 |
| commit | 08f9d5bab5092fe1193dd100765079e3e4d746b9 (patch) | |
| tree | 627588dd204f5a7c24ea79ab17076f3eeab818eb /mrbgems | |
| parent | eb070303080b24458d3740424aa7aa8a45fa49eb (diff) | |
| download | mruby-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.rake | 1 | ||||
| -rw-r--r-- | mrbgems/mruby-rational/mrblib/rational.rb | 36 | ||||
| -rw-r--r-- | mrbgems/mruby-rational/src/rational.c | 195 |
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)); } |
