Refactor integer division.

parent 37a18847
......@@ -52,6 +52,12 @@ int_overflow(mrb_state *mrb, const char *reason)
mrb_raisef(mrb, E_RANGE_ERROR, "integer overflow in %s", reason);
}
static void
int_zerodiv(mrb_state *mrb)
{
mrb_raise(mrb, E_ZERODIV_ERROR, "divided by 0");
}
/*
* call-seq:
*
......@@ -67,10 +73,9 @@ int_pow(mrb_state *mrb, mrb_value x)
mrb_int base = mrb_int(mrb, x);
mrb_int exp;
#ifndef MRB_NO_FLOAT
mrb_value y;
mrb_value y = mrb_get_arg1(mrb);
mrb_float z;
mrb_get_args(mrb, "o", &y);
if (!mrb_integer_p(y)) {
mrb_get_args(mrb, "f", &z);
z = pow((mrb_float)base, z);
......@@ -112,7 +117,7 @@ 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");
int_zerodiv(mrb);
}
else if(x == MRB_INT_MIN && y == -1) {
int_overflow(mrb, "division");
......@@ -120,10 +125,8 @@ mrb_num_div_int(mrb_state *mrb, mrb_int x, mrb_int y)
else {
mrb_int div = x / y;
if (div < 0) {
if (x != div * y) {
div -= 1;
}
if ((x ^ y) < 0 && x != div * y) {
div -= 1;
}
return div;
}
......@@ -144,31 +147,11 @@ mrb_num_div_int(mrb_state *mrb, mrb_int x, mrb_int y)
static mrb_value
int_div(mrb_state *mrb, mrb_value xv)
{
#ifndef MRB_NO_FLOAT
mrb_value yv;
mrb_get_args(mrb, "o", &yv);
if (mrb_float_p(yv)) {
double d = mrb_integer(xv)/mrb_float(yv);
#ifdef MRB_INT32
if (MRB_INT_MIN <= d && d <= MRB_INT_MAX)
return mrb_int_value(mrb, (mrb_int)d);
return mrb_float_value(mrb, d);
#else
return mrb_int_value(mrb, (mrb_int)d);
#endif
}
else
#endif
{
mrb_int y;
mrb_int y, div;
mrb_get_args(mrb, "i", &y);
if (y == 0) {
mrb_raise(mrb, E_ZERODIV_ERROR, "devided by zero");
}
return mrb_int_value(mrb, mrb_integer(xv) / y);
}
mrb_get_args(mrb, "i", &y);
div = mrb_num_div_int(mrb, mrb_integer(xv), y);
return mrb_int_value(mrb, div);
}
/* 15.2.9.3.19(x) */
......@@ -187,14 +170,11 @@ int_quo(mrb_state *mrb, mrb_value xv)
mrb_get_args(mrb, "i", &y);
if (y == 0) {
mrb_raise(mrb, E_ZERODIV_ERROR, "devided by zero");
int_zerodiv(mrb);
}
return mrb_fixnum_value(mrb_fixnum(xv) / y);
#else
mrb_float y;
mrb_get_args(mrb, "f", &y);
return mrb_float_value(mrb, (mrb_float)mrb_integer(xv) / y);
return int_div(mrb, xv);
#endif
}
......@@ -233,19 +213,13 @@ flo_pow(mrb_state *mrb, mrb_value x)
}
static mrb_value
flo_idiv(mrb_state *mrb, mrb_value x)
flo_idiv(mrb_state *mrb, mrb_value xv)
{
mrb_float y;
mrb_int y, div;
mrb_get_args(mrb, "f", &y);
y = mrb_to_flo(mrb, x) / y;
#ifdef MRB_INT32
if (MRB_INT_MIN <= y && y <= MRB_INT_MAX)
return mrb_int_value(mrb, (mrb_int)y);
return mrb_float_value(mrb, y);
#else
return mrb_int_value(mrb, (mrb_int)y);
#endif
mrb_get_args(mrb, "i", &y);
div = mrb_num_div_int(mrb, (mrb_int)mrb_float(xv), y);
return mrb_int_value(mrb, (mrb_int)div);
}
mrb_float
......@@ -963,29 +937,23 @@ int_mul(mrb_state *mrb, mrb_value x)
static void
fixdivmod(mrb_state *mrb, mrb_int x, mrb_int y, mrb_int *divp, mrb_int *modp)
{
mrb_int div, mod;
/* TODO: add mrb_assert(y != 0) to make sure */
if (y < 0) {
if (x < 0)
div = -x / -y;
else
div = - (x / -y);
if (y == 0) {
int_zerodiv(mrb);
}
else {
if (x < 0)
div = - (-x / y);
else
div = x / y;
else if(x == MRB_INT_MIN && y == -1) {
int_overflow(mrb, "division");
}
mod = x - div*y;
if ((mod < 0 && y > 0) || (mod > 0 && y < 0)) {
mod += y;
div -= 1;
else {
mrb_int div = x / y;
mrb_int mod = x - div * y;
if ((x ^ y) < 0 && x != div * y) {
mod += y;
div -= 1;
}
if (divp) *divp = div;
if (modp) *modp = mod;
}
if (divp) *divp = div;
if (modp) *modp = mod;
}
/* 15.2.8.3.5 */
......@@ -1008,9 +976,6 @@ int_mod(mrb_state *mrb, mrb_value x)
if (mrb_integer_p(y) && a != MRB_INT_MIN && (b=mrb_integer(y)) != MRB_INT_MIN) {
mrb_int mod;
if (b == 0) {
mrb_raise(mrb, E_ZERODIV_ERROR, "divided by 0");
}
fixdivmod(mrb, a, b, NULL, &mod);
return mrb_fixnum_value(mod);
}
......@@ -1040,9 +1005,6 @@ int_divmod(mrb_state *mrb, mrb_value x)
if (mrb_integer_p(y)) {
mrb_int div, mod;
if (mrb_integer(y) == 0) {
mrb_raise(mrb, E_ZERODIV_ERROR, "divided by 0");
}
fixdivmod(mrb, mrb_integer(x), mrb_integer(y), &div, &mod);
return mrb_assoc_new(mrb, mrb_int_value(mrb, div), mrb_int_value(mrb, mod));
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment