diff --git a/mrbgems/mruby-bigint/core/bigint.c b/mrbgems/mruby-bigint/core/bigint.c index 0bf330276..dff4b70dd 100644 --- a/mrbgems/mruby-bigint/core/bigint.c +++ b/mrbgems/mruby-bigint/core/bigint.c @@ -312,18 +312,16 @@ mpz_add(mrb_state *mrb, mpz_t *zz, mpz_t *x, mpz_t *y) mpz_move(mrb, zz, &z); } -/* x = x + n (only called from mpz_init_set_str) */ -/* assumes x and n are positive or zero */ -/* assumes n is small (fits in mp_limb) */ +/* x += n */ +/* ignores sign of x */ +/* assumes n is positive and small (fits in mp_limb) */ static void mpz_add_int(mrb_state *mrb, mpz_t *x, mrb_int n) { - if (n == 0) { - // If n is zero, no operation is needed - return; - } + // If n is zero, no operation is needed + if (n == 0) return; - // Assume x is positive and n is a small positive integer (n < 36) + // Assume x is positive and n is a small positive integer mp_dbl_limb carry = n; // Initialize carry with n for (size_t i = 0; i < x->sz && carry; i++) { carry += (mp_dbl_limb)x->p[i]; // Add current limb and carry @@ -352,20 +350,26 @@ mpz_sub(mrb_state *mrb, mpz_t *z, mpz_t *x, mpz_t *y) mpz_add(mrb, z, x, &u); } -/* x -= n */ -/* assumes n is small (fits in mp_limb) */ +/* x -= n */ +/* ignores sign of x */ +/* assumes n is positive and small (fits in mp_limb) */ static void mpz_sub_int(mrb_state *mrb, mpz_t *x, mrb_int n) { - // If x is zero, set x to -1 + // If n is zero, no operation is needed + if (n == 0) return; + + // If x is zero, set x to n if (zero_p(x) || x->sz == 0) { mpz_set_int(mrb, x, n); return; } + #if 0 if (x->sn < 0) { - mpz_add_int(mrb, x, 1); + mpz_add_int(mrb, x, n); return; } + #endif // Initialize borrow and start decrement mp_dbl_limb_signed borrow = (mp_limb)n; @@ -1480,22 +1484,17 @@ mrb_bint_as_uint64(mrb_state *mrb, mrb_value x) static mrb_bool int_fit_limb_p(mrb_int i) { -#ifdef MRB_INT64 #if DIG_SIZE == 32 +# ifdef MRB_INT64 // if mp_limb is int32_t - return (i >= INT32_MIN && i <= INT32_MAX); -#else /* if DIG_SIZE == 16 */ - // if mp_limb is int16_t - return (i >= INT16_MIN && i <= INT16_MAX); -#endif -#else /* MRB_INT32 */ -#if DIG_SIZE == 32 + return (i > INT32_MIN && i <= INT32_MAX); +# else // if mp_limb is also int32_t, it always fits return TRUE; +# endif #else /* if DIG_SIZE == 16 */ // if mp_limb is int16_t - return (i >= INT16_MIN && i <= INT16_MAX); -#endif + return (i > INT16_MIN && i <= INT16_MAX); #endif } @@ -1507,14 +1506,25 @@ mrb_bint_add_n(mrb_state *mrb, mrb_value x, mrb_value y) bint_as_mpz(RBIGINT(x), &a); if (mrb_integer_p(y)) { - mrb_int i = mrb_integer(y); - if (int_fit_limb_p(i)) { + mrb_int n = mrb_integer(y); + if (int_fit_limb_p(n)) { mpz_init_set(mrb, &z, &a); - if ((i > 0) ^ (z.sn > 0)) { - mpz_sub_int(mrb, &z, i); + if (n > 0) { + if (z.sn > 0) { + mpz_add_int(mrb, &z, n); + } + else { + mpz_sub_int(mrb, &z, n); + } } else { - mpz_add_int(mrb, &z, i); + n = -n; + if (z.sn > 0) { + mpz_sub_int(mrb, &z, n); + } + else { + mpz_add_int(mrb, &z, n); + } } struct RBigint *v = bint_new(mrb, &z); return mrb_obj_value(v); @@ -1550,14 +1560,25 @@ mrb_bint_sub_n(mrb_state *mrb, mrb_value x, mrb_value y) bint_as_mpz(RBIGINT(x), &a); if (mrb_integer_p(y)) { - mrb_int i = mrb_integer(y); - if (int_fit_limb_p(i)) { + mrb_int n = mrb_integer(y); + if (int_fit_limb_p(n)) { mpz_init_set(mrb, &z, &a); - if ((i > 0) ^ (z.sn > 0)) { - mpz_add_int(mrb, &z, i); + if (n > 0) { + if (z.sn > 0) { + mpz_sub_int(mrb, &z, n); + } + else { + mpz_add_int(mrb, &z, n); + } } else { - mpz_sub_int(mrb, &z, i); + n = -n; + if (z.sn > 0) { + mpz_add_int(mrb, &z, n); + } + else { + mpz_sub_int(mrb, &z, n); + } } struct RBigint *v = bint_new(mrb, &z); return mrb_obj_value(v);