mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-bigint: improve mpz_mul_int() and mpz_add_int()
Both functions are only called from mpz_init_set_str(). We can assume - mpz_t is modifiable - mpz_t is positive - n is positive and small (n <= 36) Those new definitions consume less memory and are slightly faster.
This commit is contained in:
@@ -310,17 +310,6 @@ mpz_add(mrb_state *mrb, mpz_t *zz, mpz_t *x, mpz_t *y)
|
||||
mpz_move(mrb, zz, &z);
|
||||
}
|
||||
|
||||
/* x = y - n */
|
||||
static void
|
||||
mpz_add_int(mrb_state *mrb, mpz_t *x, mpz_t *y, mrb_int n)
|
||||
{
|
||||
mpz_t z;
|
||||
|
||||
mpz_init_set_int(mrb, &z, n);
|
||||
mpz_add(mrb, x, y, &z);
|
||||
mpz_clear(mrb, &z);
|
||||
}
|
||||
|
||||
/* z = x - y -- just use mpz_add - I'm lazy */
|
||||
static void
|
||||
mpz_sub(mrb_state *mrb, mpz_t *z, mpz_t *x, mpz_t *y)
|
||||
@@ -381,20 +370,6 @@ mpz_mul(mrb_state *mrb, mpz_t *ww, mpz_t *u, mpz_t *v)
|
||||
mpz_move(mrb, ww, &w);
|
||||
}
|
||||
|
||||
static void
|
||||
mpz_mul_int(mrb_state *mrb, mpz_t *x, mpz_t *y, mrb_int n)
|
||||
{
|
||||
if (n == 0) {
|
||||
zero(x);
|
||||
return;
|
||||
}
|
||||
|
||||
mpz_t z;
|
||||
mpz_init_set_int(mrb, &z, n);
|
||||
mpz_mul(mrb, x, y, &z);
|
||||
mpz_clear(mrb, &z);
|
||||
}
|
||||
|
||||
/* number of leading zero bits in digit */
|
||||
static int
|
||||
lzb(mp_limb x)
|
||||
@@ -677,13 +652,78 @@ mpz_sizeinbase(mpz_t *x, mrb_int base)
|
||||
return bits/(j-1)+1;
|
||||
}
|
||||
|
||||
/* x = y * n (only called from mpz_init_set_str) */
|
||||
/* assumes x and n are positive or zero */
|
||||
/* assumes n is small (fits in mp_limb) */
|
||||
static void
|
||||
mpz_mul_int(mrb_state *mrb, mpz_t *x, mrb_int n)
|
||||
{
|
||||
if (n == 0 || zero_p(x)) {
|
||||
zero(x);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t x_sz = x->sz;
|
||||
size_t new_sz = x_sz + 1; // Maximum possible size after multiplication
|
||||
|
||||
// Reallocate x if necessary
|
||||
mpz_realloc(mrb, x, new_sz);
|
||||
|
||||
mp_dbl_limb cc = 0;
|
||||
mp_limb n_limb = (mp_limb)n;
|
||||
|
||||
for (size_t i = 0; i < x_sz; i++) {
|
||||
// Multiply each limb and add carry
|
||||
cc += (mp_dbl_limb)x->p[i] * n_limb;
|
||||
x->p[i] = LOW(cc);
|
||||
cc = HIGH(cc);
|
||||
}
|
||||
|
||||
if (cc) {
|
||||
// If there is a remaining carry, store it
|
||||
x->p[x_sz] = (mp_limb)cc;
|
||||
} else {
|
||||
x->sz = x_sz;
|
||||
}
|
||||
|
||||
x->sn = 1;
|
||||
trim(x);
|
||||
}
|
||||
|
||||
/* x = y + n (only called from mpz_init_set_str) */
|
||||
/* assumes x and n are positive or zero */
|
||||
/* assumes n is 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;
|
||||
}
|
||||
|
||||
// Assume x is positive and n is a small positive integer (n < 36)
|
||||
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
|
||||
x->p[i] = LOW(carry); // Store lower 32 bits in current limb
|
||||
carry = HIGH(carry); // Update carry with higher bits
|
||||
}
|
||||
|
||||
if (carry != 0) {
|
||||
mpz_realloc(mrb, x, x->sz + 1);
|
||||
x->p[x->sz-1] = (mp_limb)carry;
|
||||
x->sn = 1;
|
||||
}
|
||||
trim(x);
|
||||
}
|
||||
|
||||
static int
|
||||
mpz_init_set_str(mrb_state *mrb, mpz_t *x, const char *s, mrb_int len, mrb_int base)
|
||||
{
|
||||
int retval = 0;
|
||||
short sn;
|
||||
uint8_t k;
|
||||
mpz_init(mrb, x);
|
||||
|
||||
zero(x);
|
||||
if (*s == '-') {
|
||||
sn = -1; s++;
|
||||
@@ -706,8 +746,8 @@ mpz_init_set_str(mrb_state *mrb, mpz_t *x, const char *s, mrb_int len, mrb_int b
|
||||
retval = (-1);
|
||||
break;
|
||||
}
|
||||
mpz_mul_int(mrb, x, x, base);
|
||||
mpz_add_int(mrb, x, x, k);
|
||||
mpz_mul_int(mrb, x, base);
|
||||
mpz_add_int(mrb, x, k);
|
||||
}
|
||||
x->sn = sn;
|
||||
return retval;
|
||||
|
||||
Reference in New Issue
Block a user