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
MODIFY
include/mruby/value.h
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
};

MODIFY
mrbgems/mruby-rational/mrbgem.rake
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

MODIFY
mrbgems/mruby-rational/mrblib/rational.rb
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

MODIFY
mrbgems/mruby-rational/src/rational.c
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));
}

MODIFY
src/gc.c
src/gc.c
@@ -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;
}

MODIFY
src/numeric.c
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,21 +143,28 @@ 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);
+ 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,14 +902,22 @@ 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));
#endif
}
+}
MRB_API mrb_value
mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y)
@@ -895,6 +929,15 @@ mrb_num_mul(mrb_state *mrb, mrb_value x, mrb_value y)
if (mrb_float_p(x)) {
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;
@@ -1048,6 +1091,14 @@ int_equal(mrb_state *mrb, mrb_value x)
#ifndef MRB_NO_FLOAT
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,12 +1343,20 @@ 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));
#endif
}
+}
MRB_API mrb_value
mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y)
@@ -1309,6 +1368,15 @@ mrb_num_plus(mrb_state *mrb, mrb_value x, mrb_value y)
if (mrb_float_p(x)) {
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,12 +1414,21 @@ 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));
#endif
}
+}
MRB_API mrb_value
mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y)
@@ -1363,6 +1440,15 @@ mrb_num_minus(mrb_state *mrb, mrb_value x, mrb_value y)
if (mrb_float_p(x)) {
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 */
@@ -1471,6 +1557,11 @@ cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2)
case MRB_TT_FLOAT:
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 */

MODIFY
src/object.c
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;
}

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