summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/numeric.c66
-rw-r--r--src/vm.c43
2 files changed, 60 insertions, 49 deletions
diff --git a/src/numeric.c b/src/numeric.c
index 9fdaf2542..e1898301e 100644
--- a/src/numeric.c
+++ b/src/numeric.c
@@ -101,6 +101,41 @@ int_pow(mrb_state *mrb, mrb_value x)
#endif
}
+
+mrb_int
+mrb_num_div_int(mrb_state *mrb, mrb_int x, mrb_int y)
+{
+ if (y == 0) {
+ mrb_raise(mrb, E_ZERODIV_ERROR, "divided by 0");
+ }
+ else if(x == MRB_INT_MIN && y == -1) {
+ mrb_raise(mrb, E_RANGE_ERROR, "integer overflow in division");
+ }
+ else {
+ mrb_int div, mod;
+
+ if (y < 0) {
+ if (x < 0)
+ div = -x / -y;
+ else
+ div = - (x / -y);
+ }
+ else {
+ if (x < 0)
+ div = - (-x / y);
+ else
+ div = x / y;
+ }
+ mod = x - div * y;
+ if ((mod < 0 && y > 0) || (mod > 0 && y < 0)) {
+ div -= 1;
+ }
+ return div;
+ }
+ /* not reached */
+ return 0;
+}
+
/* 15.2.8.3.4 */
/* 15.2.9.3.4 */
/*
@@ -111,7 +146,6 @@ int_pow(mrb_state *mrb, mrb_value x)
* the class of <code>num</code> and on the magnitude of the
* result.
*/
-
static mrb_value
int_div(mrb_state *mrb, mrb_value xv)
{
@@ -219,23 +253,31 @@ flo_idiv(mrb_state *mrb, mrb_value x)
#endif
}
+mrb_float
+mrb_num_div_flo(mrb_state *mrb, mrb_float x, mrb_float y)
+{
+ mrb_float f;
+
+ if (y == 0) {
+ if (x > 0) f = INFINITY;
+ else if (x < 0) f = -INFINITY;
+ else /* if (x == 0) */ f = NAN;
+ }
+ else {
+ f = x / y;
+ }
+ return f;
+}
+
static mrb_value
flo_div(mrb_state *mrb, mrb_value xv)
{
mrb_float x, y;
- mrb_get_args(mrb, "f", &y);
x = mrb_float(xv);
- if (y == 0) {
- if (x < 0)
- y = -INFINITY;
- else if (x > 0)
- y = INFINITY;
- else /* if (x == 0) */
- y = NAN;
- return mrb_float_value(mrb, y);
- }
- return mrb_float_value(mrb, x / y);
+ mrb_get_args(mrb, "f", &y);
+ x = mrb_num_div_flo(mrb, x, y);
+ return mrb_float_value(mrb, x);
}
static mrb_value
diff --git a/src/vm.c b/src/vm.c
index 2e3024cd8..7f79db32b 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -2309,8 +2309,10 @@ RETRY_TRY_BLOCK:
}
CASE(OP_DIV, B) {
+ mrb_int mrb_num_div_int(mrb_state *mrb, mrb_int x, mrb_int y);
#ifndef MRB_NO_FLOAT
- double x, y, f;
+ mrb_float mrb_num_div_flo(mrb_state *mrb, mrb_float x, mrb_float y);
+ mrb_float x, y, f;
#endif
/* need to check if op is overridden */
@@ -2319,34 +2321,8 @@ RETRY_TRY_BLOCK:
{
mrb_int x = mrb_integer(regs[a]);
mrb_int y = mrb_integer(regs[a+1]);
-
-
- if (y == 0) {
- mrb_raise(mrb, E_ZERODIV_ERROR, "divided by 0");
- }
- else if(x == MRB_INT_MIN && y == -1) {
- mrb_raise(mrb, E_RANGE_ERROR, "integer overflow in division");
- }
- else {
- mrb_int div, mod;
- if (y < 0) {
- if (x < 0)
- div = -x / -y;
- else
- div = - (x / -y);
- }
- else {
- if (x < 0)
- div = - (-x / y);
- else
- div = x / y;
- }
- mod = x - div*y;
- if ((mod < 0 && y > 0) || (mod > 0 && y < 0)) {
- div -= 1;
- }
- SET_INT_VALUE(mrb, regs[a], div);
- }
+ mrb_int div = mrb_num_div_int(mrb, x, y);
+ SET_INT_VALUE(mrb, regs[a], div);
}
goto L_DIV_OUT;
#ifndef MRB_NO_FLOAT
@@ -2370,14 +2346,7 @@ RETRY_TRY_BLOCK:
}
#ifndef MRB_NO_FLOAT
- if (y == 0) {
- if (x > 0) f = INFINITY;
- else if (x < 0) f = -INFINITY;
- else /* if (x == 0) */ f = NAN;
- }
- else {
- f = x / y;
- }
+ f = mrb_num_div_flo(mrb, x, y);
SET_FLOAT_VALUE(mrb, regs[a], f);
#endif
L_DIV_OUT: