summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/mruby/numeric.h5
-rw-r--r--src/numeric.c198
-rw-r--r--src/vm.c39
3 files changed, 133 insertions, 109 deletions
diff --git a/include/mruby/numeric.h b/include/mruby/numeric.h
index 1bea51152..95792e9a6 100644
--- a/include/mruby/numeric.h
+++ b/include/mruby/numeric.h
@@ -22,6 +22,11 @@ mrb_value mrb_flt2big(mrb_state *mrb, mrb_float d);
void mrb_num_zerodiv(mrb_state *mrb);
mrb_value mrb_fix2str(mrb_state *mrb, mrb_value x, int base);
+mrb_value mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y);
+mrb_value mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y);
+mrb_value mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y);
+mrb_value mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y);
+
#if defined(__cplusplus)
} /* extern "C" { */
#endif
diff --git a/src/numeric.c b/src/numeric.c
index e1f711478..2d668fa79 100644
--- a/src/numeric.c
+++ b/src/numeric.c
@@ -118,6 +118,12 @@ num_pow(mrb_state *mrb, mrb_value x)
* result.
*/
+mrb_value
+mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y)
+{
+ return mrb_float_value(mrb_to_flo(mrb, x) / mrb_to_flo(mrb, y));
+}
+
/* 15.2.9.3.19(x) */
/*
* call-seq:
@@ -404,7 +410,7 @@ flo_to_f(mrb_state *mrb, mrb_value num)
*/
static mrb_value
-flo_is_infinite_p(mrb_state *mrb, mrb_value num)
+flo_infinite_p(mrb_state *mrb, mrb_value num)
{
mrb_float value = mrb_float(num);
@@ -426,7 +432,7 @@ flo_is_infinite_p(mrb_state *mrb, mrb_value num)
*/
static mrb_value
-flo_is_finite_p(mrb_state *mrb, mrb_value num)
+flo_finite_p(mrb_state *mrb, mrb_value num)
{
mrb_float value = mrb_float(num);
@@ -691,9 +697,31 @@ int_succ(mrb_state *mrb, mrb_value num)
return mrb_funcall(mrb, num, "+", 1, mrb_fixnum_value(1));
}
-#define SQRT_LONG_MAX ((SIGNED_VALUE)1<<((sizeof(mrb_int)*CHAR_BIT-1)/2))
+#define SQRT_INT_MAX ((SIGNED_VALUE)1<<((sizeof(mrb_int)*CHAR_BIT-1)/2))
/*tests if N*N would overflow*/
-#define FIT_SQRT_LONG(n) (((n)<SQRT_LONG_MAX)&&((n)>=-SQRT_LONG_MAX))
+#define FIT_SQRT_INT(n) (((n)<SQRT_INT_MAX)&&((n)>=-SQRT_INT_MAX))
+
+mrb_value
+mrb_fixnum_mul(mrb_state *mrb, mrb_value x, mrb_value y)
+{
+ mrb_int a;
+
+ a = mrb_fixnum(x);
+ if (a == 0) return x;
+ if (FIXNUM_P(y)) {
+ mrb_int b, c;
+
+ b = mrb_fixnum(y);
+ if (FIT_SQRT_INT(a) && FIT_SQRT_INT(b))
+ return mrb_fixnum_value(a*b);
+ c = a * b;
+ if (c/a != b) {
+ return mrb_float_value((mrb_float)a*(mrb_float)b);
+ }
+ return mrb_fixnum_value(c);;
+ }
+ return mrb_float_value((mrb_float)a * mrb_to_flo(mrb, y));
+}
/* 15.2.8.3.3 */
/*
@@ -709,27 +737,8 @@ static mrb_value
fix_mul(mrb_state *mrb, mrb_value x)
{
mrb_value y;
- mrb_int a;
mrb_get_args(mrb, "o", &y);
-
- a = mrb_fixnum(x);
- if (FIXNUM_P(y)) {
- mrb_int b, c;
- mrb_value r;
-
- b = mrb_fixnum(y);
- if (FIT_SQRT_LONG(a) && FIT_SQRT_LONG(b))
- return mrb_fixnum_value(a*b);
- c = a * b;
- r = mrb_fixnum_value(c);
-
- if (a == 0) return x;
- if (mrb_fixnum(r) != c || c/a != b) {
- r = mrb_float_value((mrb_float)a*(mrb_float)b);
- }
- return r;
- }
- return mrb_float_value((mrb_float)a * mrb_to_flo(mrb, y));
+ return mrb_fixnum_mul(mrb, x, y);
}
static void
@@ -942,8 +951,28 @@ fix_xor(mrb_state *mrb, mrb_value x)
return mrb_fixnum_value(val);
}
-static mrb_value fix_lshift(mrb_state *mrb, mrb_int, unsigned long);
-static mrb_value fix_rshift(mrb_int, unsigned long);
+static mrb_value
+lshift(mrb_state *mrb, mrb_int val, unsigned long width)
+{
+ if (width > (sizeof(mrb_int)*CHAR_BIT-1)
+ || ((unsigned long)abs(val))>>(sizeof(mrb_int)*CHAR_BIT-1-width) > 0) {
+ mrb_raise(mrb, E_RANGE_ERROR, "width(%d) > (%d:sizeof(mrb_int)*CHAR_BIT-1)", width,
+ sizeof(mrb_int)*CHAR_BIT-1);
+ }
+ val = val << width;
+ return mrb_fixnum_value(val);
+}
+
+static mrb_value
+rshift(mrb_int val, unsigned long i)
+{
+ if (i >= sizeof(mrb_int)*CHAR_BIT-1) {
+ if (val < 0) return mrb_fixnum_value(-1);
+ return mrb_fixnum_value(0);
+ }
+ val = RSHIFT(val, i);
+ return mrb_fixnum_value(val);
+}
/* 15.2.8.3.12 */
/*
@@ -954,7 +983,7 @@ static mrb_value fix_rshift(mrb_int, unsigned long);
*/
static mrb_value
-mrb_fix_lshift(mrb_state *mrb, mrb_value x)
+fix_lshift(mrb_state *mrb, mrb_value x)
{
mrb_value y;
mrb_int val, width;
@@ -964,20 +993,8 @@ mrb_fix_lshift(mrb_state *mrb, mrb_value x)
y = bit_coerce(mrb, y);
width = mrb_fixnum(y);
if (width < 0)
- return fix_rshift(val, (unsigned long)-width);
- return fix_lshift(mrb, val, width);
-}
-
-static mrb_value
-fix_lshift(mrb_state *mrb, mrb_int val, unsigned long width)
-{
- if (width > (sizeof(mrb_int)*CHAR_BIT-1)
- || ((unsigned long)abs(val))>>(sizeof(mrb_int)*CHAR_BIT-1-width) > 0) {
- mrb_raise(mrb, E_RANGE_ERROR, "width(%d) > (%d:sizeof(mrb_int)*CHAR_BIT-1)", width,
- sizeof(mrb_int)*CHAR_BIT-1);
- }
- val = val << width;
- return mrb_fixnum_value(val);
+ return rshift(val, (unsigned long)-width);
+ return lshift(mrb, val, width);
}
/* 15.2.8.3.13 */
@@ -989,7 +1006,7 @@ fix_lshift(mrb_state *mrb, mrb_int val, unsigned long width)
*/
static mrb_value
-mrb_fix_rshift(mrb_state *mrb, mrb_value x)
+fix_rshift(mrb_state *mrb, mrb_value x)
{
mrb_value y;
mrb_int i, val;
@@ -1000,19 +1017,8 @@ mrb_fix_rshift(mrb_state *mrb, mrb_value x)
i = mrb_fixnum(y);
if (i == 0) return x;
if (i < 0)
- return fix_lshift(mrb, val, (unsigned long)-i);
- return fix_rshift(val, i);
-}
-
-static mrb_value
-fix_rshift(mrb_int val, unsigned long i)
-{
- if (i >= sizeof(mrb_int)*CHAR_BIT-1) {
- if (val < 0) return mrb_fixnum_value(-1);
- return mrb_fixnum_value(0);
- }
- val = RSHIFT(val, i);
- return mrb_fixnum_value(val);
+ return lshift(mrb, val, (unsigned long)-i);
+ return rshift(val, i);
}
/* 15.2.8.3.23 */
@@ -1066,7 +1072,27 @@ flt2big(mrb_state *mrb, mrb_float d)
mrb_value
mrb_flt2big(mrb_state *mrb, mrb_float d)
{
- return mrb_fixnum_value(flt2big(mrb, d));
+ return mrb_fixnum_value(flt2big(mrb, d));
+}
+
+mrb_value
+mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y)
+{
+ mrb_int a;
+
+ a = mrb_fixnum(x);
+ if (a == 0) return y;
+ if (FIXNUM_P(y)) {
+ mrb_int b, c;
+
+ b = mrb_fixnum(y);
+ c = a + b;
+ if (c - b != a) {
+ return mrb_float_value((mrb_float)a + (mrb_float)b);
+ }
+ return mrb_fixnum_value(c);
+ }
+ return mrb_float_value((mrb_float)a + mrb_to_flo(mrb, y));
}
/* 15.2.8.3.1 */
@@ -1079,15 +1105,32 @@ mrb_flt2big(mrb_state *mrb, mrb_float d)
* result.
*/
static mrb_value
-mrb_fixnum_plus(mrb_state *mrb, mrb_value self)
+fix_plus(mrb_state *mrb, mrb_value self)
{
- mrb_int x, y;
+ mrb_value other;
+
+ mrb_get_args(mrb, "o", &other);
+ return mrb_fixnum_plus(mrb, self, other);
+}
- x = mrb_fixnum(self);
- mrb_get_args(mrb, "i", &y);
+mrb_value
+mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y)
+{
+ mrb_int a;
+
+ a = mrb_fixnum(x);
+ if (a == 0) return y;
+ if (FIXNUM_P(y)) {
+ mrb_int b, c;
- DEBUG(printf("%d + %d = %d\n", x, y, x+y));
- return mrb_fixnum_value(x + y);
+ b = mrb_fixnum(y);
+ c = a - b;
+ if (c + b != a) {
+ return mrb_float_value((mrb_float)a - (mrb_float)b);
+ }
+ return mrb_fixnum_value(c);
+ }
+ return mrb_float_value((mrb_float)a - mrb_to_flo(mrb, y));
}
/* 15.2.8.3.2 */
@@ -1101,15 +1144,12 @@ mrb_fixnum_plus(mrb_state *mrb, mrb_value self)
* result.
*/
static mrb_value
-mrb_fixnum_minus(mrb_state *mrb, mrb_value self)
+fix_minus(mrb_state *mrb, mrb_value self)
{
- mrb_int x, y;
-
- x = mrb_fixnum(self);
- mrb_get_args(mrb, "i", &y);
+ mrb_value other;
- DEBUG(printf("%d - %d = %d\n", x, y, x-y));
- return mrb_fixnum_value(x - y);
+ mrb_get_args(mrb, "o", &other);
+ return mrb_fixnum_minus(mrb, self, other);
}
/* 15.2.8.3.29 (x) */
@@ -1179,7 +1219,7 @@ mrb_fix_to_s(mrb_state *mrb, mrb_value self, int argc, mrb_value *argv)
*
*/
static mrb_value
-mrb_fixnum_to_s(mrb_state *mrb, mrb_value self) /* fix_to_s */
+fix_to_s(mrb_state *mrb, mrb_value self) /* fix_to_s */
{
mrb_value *argv;
int argc;
@@ -1236,7 +1276,7 @@ num_cmp(mrb_state *mrb, mrb_value self)
* and <code>other</code>.
*/
static mrb_value
-mrb_float_plus(mrb_state *mrb, mrb_value self)
+flo_plus(mrb_state *mrb, mrb_value self)
{
mrb_float x, y;
@@ -1267,8 +1307,8 @@ mrb_init_numeric(mrb_state *mrb)
fixnum = mrb->fixnum_class = mrb_define_class(mrb, "Fixnum", integer);
mrb_undef_method(mrb, fixnum, "new");
- mrb_define_method(mrb, fixnum, "+", mrb_fixnum_plus, ARGS_REQ(1)); /* 15.2.8.3.1 */
- mrb_define_method(mrb, fixnum, "-", mrb_fixnum_minus, ARGS_REQ(1)); /* 15.2.8.3.2 */
+ mrb_define_method(mrb, fixnum, "+", fix_plus, ARGS_REQ(1)); /* 15.2.8.3.1 */
+ mrb_define_method(mrb, fixnum, "-", fix_minus, ARGS_REQ(1)); /* 15.2.8.3.2 */
mrb_define_method(mrb, fixnum, "-@", fix_uminus, ARGS_REQ(1)); /* 15.2.7.4.2 */
mrb_define_method(mrb, fixnum, "*", fix_mul, ARGS_REQ(1)); /* 15.2.8.3.3 */
mrb_define_method(mrb, fixnum, "%", fix_mod, ARGS_REQ(1)); /* 15.2.8.3.5 */
@@ -1277,8 +1317,8 @@ mrb_init_numeric(mrb_state *mrb)
mrb_define_method(mrb, fixnum, "&", fix_and, ARGS_REQ(1)); /* 15.2.8.3.9 */
mrb_define_method(mrb, fixnum, "|", fix_or, ARGS_REQ(1)); /* 15.2.8.3.10 */
mrb_define_method(mrb, fixnum, "^", fix_xor, ARGS_REQ(1)); /* 15.2.8.3.11 */
- mrb_define_method(mrb, fixnum, "<<", mrb_fix_lshift, ARGS_REQ(1)); /* 15.2.8.3.12 */
- mrb_define_method(mrb, fixnum, ">>", mrb_fix_rshift, ARGS_REQ(1)); /* 15.2.8.3.13 */
+ mrb_define_method(mrb, fixnum, "<<", fix_lshift, ARGS_REQ(1)); /* 15.2.8.3.12 */
+ mrb_define_method(mrb, fixnum, ">>", fix_rshift, ARGS_REQ(1)); /* 15.2.8.3.13 */
mrb_define_method(mrb, fixnum, "ceil", int_to_i, ARGS_NONE()); /* 15.2.8.3.14 */
mrb_define_method(mrb, fixnum, "eql?", num_eql, ARGS_REQ(1)); /* 15.2.8.3.16 */
mrb_define_method(mrb, fixnum, "floor", num_floor, ARGS_NONE()); /* 15.2.8.3.17 */
@@ -1288,22 +1328,22 @@ mrb_init_numeric(mrb_state *mrb)
mrb_define_method(mrb, fixnum, "succ", fix_succ, ARGS_NONE()); /* 15.2.8.3.21 */
mrb_define_method(mrb, fixnum, "to_f", fix_to_f, ARGS_NONE()); /* 15.2.8.3.23 */
mrb_define_method(mrb, fixnum, "to_i", int_to_i, ARGS_NONE()); /* 15.2.8.3.24 */
- mrb_define_method(mrb, fixnum, "to_s", mrb_fixnum_to_s, ARGS_NONE()); /* 15.2.8.3.25 */
+ mrb_define_method(mrb, fixnum, "to_s", fix_to_s, ARGS_NONE()); /* 15.2.8.3.25 */
mrb_define_method(mrb, fixnum, "truncate", int_to_i, ARGS_NONE()); /* 15.2.8.3.26 */
mrb_define_method(mrb, fixnum, "divmod", fix_divmod, ARGS_REQ(1)); /* 15.2.8.3.30 (x) */
/* Float Class */
fl = mrb->float_class = mrb_define_class(mrb, "Float", numeric);
mrb_undef_method(mrb, fl, "new");
- mrb_define_method(mrb, fl, "+", mrb_float_plus, ARGS_REQ(1)); /* 15.2.9.3.1 */
+ mrb_define_method(mrb, fl, "+", flo_plus, ARGS_REQ(1)); /* 15.2.9.3.1 */
mrb_define_method(mrb, fl, "-", flo_minus, ARGS_REQ(1)); /* 15.2.9.3.2 */
mrb_define_method(mrb, fl, "*", flo_mul, ARGS_REQ(1)); /* 15.2.9.3.3 */
mrb_define_method(mrb, fl, "%", flo_mod, ARGS_REQ(1)); /* 15.2.9.3.5 */
mrb_define_method(mrb, fl, "==", flo_eq, ARGS_REQ(1)); /* 15.2.9.3.7 */
mrb_define_method(mrb, fl, "ceil", flo_ceil, ARGS_NONE()); /* 15.2.9.3.8 */
- mrb_define_method(mrb, fl, "finite?", flo_is_finite_p, ARGS_NONE()); /* 15.2.9.3.9 */
+ mrb_define_method(mrb, fl, "finite?", flo_finite_p, ARGS_NONE()); /* 15.2.9.3.9 */
mrb_define_method(mrb, fl, "floor", flo_floor, ARGS_NONE()); /* 15.2.9.3.10 */
- mrb_define_method(mrb, fl, "infinite?", flo_is_infinite_p,ARGS_NONE()); /* 15.2.9.3.11 */
+ mrb_define_method(mrb, fl, "infinite?", flo_infinite_p, ARGS_NONE()); /* 15.2.9.3.11 */
mrb_define_method(mrb, fl, "round", flo_round, ARGS_ANY()); /* 15.2.9.3.12 */
mrb_define_method(mrb, fl, "to_f", flo_to_f, ARGS_NONE()); /* 15.2.9.3.13 */
mrb_define_method(mrb, fl, "to_i", flo_truncate, ARGS_NONE()); /* 15.2.9.3.14 */
diff --git a/src/vm.c b/src/vm.c
index c449a9b3c..3d4d0370b 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -1162,12 +1162,12 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
regs[a].value.v1 = regs[a].value.v1 op regs[a+1].value.v2;\
} while(0)
-#define OP_MATH(op) do {\
+#define OP_MATH(op,iop,s) do {\
int a = GETARG_A(i);\
- /* need to check if - is overridden */\
+ /* need to check if op is overridden */\
switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {\
case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):\
- OP_MATH_BODY(op,i,i); \
+ regs[a] = iop(mrb, regs[a], regs[a+1]);\
break;\
case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):\
{\
@@ -1182,6 +1182,7 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):\
OP_MATH_BODY(op,f,f);\
break;\
+ s\
default:\
i = MKOP_ABC(OP_SEND, a, GETARG_B(i), GETARG_C(i));\
goto L_SEND;\
@@ -1190,50 +1191,28 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
CASE(OP_ADD) {
/* A B C R(A) := R(A)+R(A+1) (Syms[B]=:+,C=1)*/
- int a = GETARG_A(i);
-
- switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {
- case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):
- OP_MATH_BODY(+,i,i);
- break;
- case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):
- {
- mrb_int x = regs[a].value.i;
- mrb_float y = regs[a+1].value.f;
- SET_FLOAT_VALUE(regs[a], (mrb_float)x + y);
- }
- break;
- case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):
- OP_MATH_BODY(+,f,i);
- break;
- case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):
- OP_MATH_BODY(+,f,f);
- break;
+ OP_MATH(+,mrb_fixnum_plus,
case TYPES2(MRB_TT_STRING,MRB_TT_STRING):
regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]);
- break;
- default:
- i = MKOP_ABC(OP_SEND, a, GETARG_B(i), GETARG_C(i));
- goto L_SEND;
- }
+ break;);
NEXT;
}
CASE(OP_SUB) {
/* A B C R(A) := R(A)-R(A+1) (Syms[B]=:-,C=1)*/
- OP_MATH(-);
+ OP_MATH(-,mrb_fixnum_minus,;);
NEXT;
}
CASE(OP_MUL) {
/* A B C R(A) := R(A)*R(A+1) (Syms[B]=:*,C=1)*/
- OP_MATH(*);
+ OP_MATH(*,mrb_fixnum_mul,;);
NEXT;
}
CASE(OP_DIV) {
/* A B C R(A) := R(A)/R(A+1) (Syms[B]=:/,C=1)*/
- OP_MATH(/);
+ OP_MATH(/,mrb_num_div,;);
NEXT;
}