diff options
| -rw-r--r-- | include/mruby/value.h | 2 | ||||
| -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 | ||||
| -rw-r--r-- | src/gc.c | 11 | ||||
| -rw-r--r-- | src/numeric.c | 135 | ||||
| -rw-r--r-- | src/object.c | 5 |
7 files changed, 285 insertions, 100 deletions
diff --git a/include/mruby/value.h b/include/mruby/value.h index 4831b55af..39c01509d 100644 --- a/include/mruby/value.h +++ b/include/mruby/value.h @@ -129,6 +129,8 @@ enum mrb_vtype { MRB_TT_FIBER, MRB_TT_ISTRUCT, MRB_TT_BREAK, + MRB_TT_COMPLEX, + MRB_TT_RATIONAL, MRB_TT_MAXDEFINE }; 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)); } @@ -903,6 +903,17 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end) } break; +#if defined(MRB_INT64) && defined(MRB_32BIT) +#ifdef MRB_USE_RATIONAL + case MRB_TT_RATIONAL: + { + struct RData *o = (struct RData*)obj; + mrb_free(mrb, obj->iv_tbl); + } + break; +#endif +#endif + default: break; } diff --git a/src/numeric.c b/src/numeric.c index b931a0f35..3eba71b78 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -118,7 +118,6 @@ int_pow(mrb_state *mrb, mrb_value x) #endif } - mrb_int mrb_num_div_int(mrb_state *mrb, mrb_int x, mrb_int y) { @@ -144,20 +143,27 @@ mrb_num_div_int(mrb_state *mrb, mrb_int x, mrb_int y) /* 15.2.9.3.4 */ /* * call-seq: - * int / other -> int + * int / other -> num * * Performs division: the class of the resulting object depends on * the class of <code>num</code> and on the magnitude of the * result. */ static mrb_value -int_div(mrb_state *mrb, mrb_value xv) +int_div(mrb_state *mrb, mrb_value x) { - mrb_int y, div; + mrb_value y = mrb_get_arg1(mrb); + mrb_int a = mrb_integer(x); - mrb_get_args(mrb, "i", &y); - div = mrb_num_div_int(mrb, mrb_integer(xv), y); - return mrb_int_value(mrb, div); + if (mrb_integer_p(y)) { + mrb_int div = mrb_num_div_int(mrb, a, mrb_integer(y)); + return mrb_int_value(mrb, div); + } +#ifdef MRB_NO_FLOAT + mrb_raise(mrb, E_TYPE_ERROR, "non integer division"); +#else + return mrb_float_value(mrb, (mrb_float)a / mrb_to_flo(mrb, y)); +#endif } /* 15.2.9.3.19(x) */ @@ -168,17 +174,29 @@ int_div(mrb_state *mrb, mrb_value xv) * Returns most exact division. */ +/* + * call-seq: + * int.div(other) -> int + * + * Performs division: resulting integer. + */ static mrb_value -int_quo(mrb_state *mrb, mrb_value xv) +int_idiv(mrb_state *mrb, mrb_value x) { -#ifdef MRB_NO_FLOAT mrb_int y; mrb_get_args(mrb, "i", &y); if (y == 0) { int_zerodiv(mrb); } - return mrb_fixnum_value(mrb_integer(xv) / y); + return mrb_fixnum_value(mrb_integer(x) / y); +} + +static mrb_value +int_quo(mrb_state *mrb, mrb_value xv) +{ +#ifdef MRB_NO_FLOAT + return int_idiv(mrb, xv); #else mrb_float y; @@ -478,6 +496,14 @@ flo_eq(mrb_state *mrb, mrb_value x) return mrb_bool_value(mrb_float(x) == (mrb_float)mrb_integer(y)); case MRB_TT_FLOAT: return mrb_bool_value(mrb_float(x) == mrb_float(y)); +#ifdef MRB_USE_RATIONAL + case MRB_TT_RATIONAL: + return mrb_bool_value(mrb_float(x) == mrb_to_flo(mrb, y)); +#endif +#ifdef MRB_USE_COMPLEX + case MRB_TT_COMPLEX: + return mrb_bool_value(mrb_equal(mrb, y, x)); +#endif default: return mrb_false_value(); } @@ -876,13 +902,21 @@ fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y) if (mrb_int_mul_overflow(a, b, &c)) { int_overflow(mrb, "multiplication"); } - return mrb_fixnum_value(c); + return mrb_int_value(mrb, c); } + switch (mrb_type(y)) { +#if defined(MRB_USE_RATIONAL) || defined(MRB_USE_COMPLEX) + case MRB_TT_RATIONAL: + case MRB_TT_COMPLEX: + return mrb_funcall_id(mrb, y, MRB_OPSYM(mul), 1, x); +#endif + default: #ifdef MRB_NO_FLOAT - mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value"); + mrb_raise(mrb, E_TYPE_ERROR, "non integer multiplication"); #else - return mrb_float_value(mrb, (mrb_float)a * mrb_to_flo(mrb, y)); + return mrb_float_value(mrb, (mrb_float)a * mrb_to_flo(mrb, y)); #endif + } } MRB_API mrb_value @@ -896,6 +930,15 @@ mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y) return mrb_float_value(mrb, mrb_float(x) * mrb_to_flo(mrb, y)); } #endif +#if defined(MRB_USE_RATIONAL) || defined(MRB_USE_COMPLEX) + switch (mrb_type(x)) { + case MRB_TT_RATIONAL: + case MRB_TT_COMPLEX: + return mrb_funcall_id(mrb, x, MRB_OPSYM(mul), 1, y); + default: + break; + } +#endif mrb_raise(mrb, E_TYPE_ERROR, "no number multiply"); return mrb_nil_value(); /* not reached */ } @@ -964,7 +1007,7 @@ int_mod(mrb_state *mrb, mrb_value x) return mrb_fixnum_value(mod); } #ifdef MRB_NO_FLOAT - mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value"); + mrb_raise(mrb, E_TYPE_ERROR, "non integer modulo"); #else else { mrb_float mod; @@ -993,7 +1036,7 @@ int_divmod(mrb_state *mrb, mrb_value x) return mrb_assoc_new(mrb, mrb_int_value(mrb, div), mrb_int_value(mrb, mod)); } #ifdef MRB_NO_FLOAT - mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value"); + mrb_raise(mrb, E_TYPE_ERROR, "non integer divmod"); #else else { mrb_float div, mod; @@ -1049,6 +1092,14 @@ int_equal(mrb_state *mrb, mrb_value x) case MRB_TT_FLOAT: return mrb_bool_value((mrb_float)mrb_integer(x) == mrb_float(y)); #endif +#ifdef MRB_USE_RATIONAL + case MRB_TT_RATIONAL: + return mrb_bool_value(mrb_equal(mrb, y, x)); +#endif +#ifdef MRB_USE_COMPLEX + case MRB_TT_COMPLEX: + return mrb_bool_value(mrb_equal(mrb, y, x)); +#endif default: return mrb_false_value(); } @@ -1292,11 +1343,19 @@ fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y) } return mrb_int_value(mrb, c); } + switch (mrb_type(y)) { +#if defined(MRB_USE_RATIONAL) || defined(MRB_USE_COMPLEX) + case MRB_TT_RATIONAL: + case MRB_TT_COMPLEX: + return mrb_funcall_id(mrb, y, MRB_OPSYM(add), 1, x); +#endif + default: #ifdef MRB_NO_FLOAT - mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value"); + mrb_raise(mrb, E_TYPE_ERROR, "non integer addition"); #else - return mrb_float_value(mrb, (mrb_float)a + mrb_to_flo(mrb, y)); + return mrb_float_value(mrb, (mrb_float)a + mrb_to_flo(mrb, y)); #endif + } } MRB_API mrb_value @@ -1310,6 +1369,15 @@ mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y) return mrb_float_value(mrb, mrb_float(x) + mrb_to_flo(mrb, y)); } #endif +#if defined(MRB_USE_RATIONAL) || defined(MRB_USE_COMPLEX) + switch (mrb_type(x)) { + case MRB_TT_RATIONAL: + case MRB_TT_COMPLEX: + return mrb_funcall_id(mrb, x, MRB_OPSYM(add), 1, y); + default: + break; + } +#endif mrb_raise(mrb, E_TYPE_ERROR, "no number addition"); return mrb_nil_value(); /* not reached */ } @@ -1346,11 +1414,20 @@ fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y) } return mrb_int_value(mrb, c); } + switch (mrb_type(y)) { +#if defined(MRB_USE_RATIONAL) || defined(MRB_USE_COMPLEX) + case MRB_TT_RATIONAL: + case MRB_TT_COMPLEX: + x = mrb_funcall_id(mrb, y, MRB_OPSYM(sub), 1, x); + return mrb_funcall_id(mrb, x, MRB_OPSYM(minus), 0); +#endif + default: #ifdef MRB_NO_FLOAT - mrb_raise(mrb, E_TYPE_ERROR, "non fixnum value"); + mrb_raise(mrb, E_TYPE_ERROR, "non integer subtraction"); #else - return mrb_float_value(mrb, (mrb_float)a - mrb_to_flo(mrb, y)); + return mrb_float_value(mrb, (mrb_float)a - mrb_to_flo(mrb, y)); #endif + } } MRB_API mrb_value @@ -1364,6 +1441,15 @@ mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y) return mrb_float_value(mrb, mrb_float(x) - mrb_to_flo(mrb, y)); } #endif +#if defined(MRB_USE_RATIONAL) || defined(MRB_USE_COMPLEX) + switch (mrb_type(x)) { + case MRB_TT_RATIONAL: + case MRB_TT_COMPLEX: + return mrb_funcall_id(mrb, x, MRB_OPSYM(sub), 1, y); + default: + break; + } +#endif mrb_raise(mrb, E_TYPE_ERROR, "no number subtraction"); return mrb_nil_value(); /* not reached */ } @@ -1472,6 +1558,11 @@ cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2) y = mrb_float(v2); break; #endif +#ifdef MRB_USE_RATIONAL + case MRB_TT_RATIONAL: + y = mrb_to_flo(mrb, v2); + break; +#endif default: return -2; } @@ -1631,9 +1722,6 @@ mrb_init_numeric(mrb_state *mrb) MRB_SET_INSTANCE_TT(integer, MRB_TT_INTEGER); mrb_undef_class_method(mrb, integer, "new"); mrb_define_method(mrb, integer, "**", int_pow, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, integer, "/", int_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.6 */ - mrb_define_method(mrb, integer, "quo", int_quo, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */ - mrb_define_method(mrb, integer, "div", int_div, MRB_ARGS_REQ(1)); mrb_define_method(mrb, integer, "<=>", num_cmp, MRB_ARGS_REQ(1)); /* 15.2.8.3.1 */ mrb_define_method(mrb, integer, "<", num_lt, MRB_ARGS_REQ(1)); mrb_define_method(mrb, integer, "<=", num_le, MRB_ARGS_REQ(1)); @@ -1653,6 +1741,9 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, integer, "-", int_minus, MRB_ARGS_REQ(1)); /* 15.2.8.3.2 */ mrb_define_method(mrb, integer, "*", int_mul, MRB_ARGS_REQ(1)); /* 15.2.8.3.3 */ mrb_define_method(mrb, integer, "%", int_mod, MRB_ARGS_REQ(1)); /* 15.2.8.3.5 */ + mrb_define_method(mrb, integer, "/", int_div, MRB_ARGS_REQ(1)); /* 15.2.8.3.6 */ + mrb_define_method(mrb, integer, "quo", int_quo, MRB_ARGS_REQ(1)); /* 15.2.7.4.5 (x) */ + mrb_define_method(mrb, integer, "div", int_idiv, MRB_ARGS_REQ(1)); mrb_define_method(mrb, integer, "==", int_equal, MRB_ARGS_REQ(1)); /* 15.2.8.3.7 */ mrb_define_method(mrb, integer, "~", int_rev, MRB_ARGS_NONE()); /* 15.2.8.3.8 */ mrb_define_method(mrb, integer, "&", int_and, MRB_ARGS_REQ(1)); /* 15.2.8.3.9 */ diff --git a/src/object.c b/src/object.c index 0c6b86630..a44eab4bb 100644 --- a/src/object.c +++ b/src/object.c @@ -516,7 +516,10 @@ mrb_to_int(mrb_state *mrb, mrb_value val) return mrb_flo_to_fixnum(mrb, val); } #endif - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %Y to Integer", val); + if (mrb_string_p(val)) { + mrb_raise(mrb, E_TYPE_ERROR, "can't convert String to Integer"); + } + return mrb_type_convert(mrb, val, MRB_TT_INTEGER, MRB_SYM(to_i)); } return val; } |
