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:
Yukihiro "Matz" Matsumoto
2024-10-08 11:09:16 +09:00
parent 3b06ad4737
commit b56ad8fdee
+68 -28
View File
@@ -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;