summaryrefslogtreecommitdiffhomepage
path: root/src/numeric.c
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 /src/numeric.c
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 'src/numeric.c')
-rw-r--r--src/numeric.c135
1 files changed, 113 insertions, 22 deletions
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 */