GitHub

@@ -99,7 +99,7 @@ pool_alloc(mpz_pool_t *pool, size_t limbs)

9999100100

/* Zero n limbs at p */

101101

static inline void

102-

limb_zero(mp_limb *p, size_t n)

102+

mpn_zero(mp_limb *p, size_t n)

103103

{

104104

memset(p, 0, n * sizeof(mp_limb));

105105

}

@@ -124,7 +124,7 @@ mpz_init_heap(mpz_ctx_t *ctx, mpz_t *s, size_t hint)

124124

mrb_raise(mrb, E_RUNTIME_ERROR, "bigint size too large");

125125

}

126126

s->p = (mp_limb*)mrb_malloc(MPZ_MRB(ctx), hint * sizeof(mp_limb));

127-

limb_zero(s->p, hint);

127+

mpn_zero(s->p, hint);

128128

s->sz = hint;

129129

}

130130

else {

@@ -200,7 +200,7 @@ mpz_realloc(mpz_ctx_t *ctx, mpz_t *x, size_t size)

200200

#endif

201201202202

/* Zero-initialize new limbs */

203-

limb_zero(x->p + old_sz, size - old_sz);

203+

mpn_zero(x->p + old_sz, size - old_sz);

204204

x->sz = size;

205205

}

206206

}

@@ -638,7 +638,7 @@ mpz_sub_int(mpz_ctx_t *ctx, mpz_t *x, mrb_int n)

638638639639

/* Multiply-and-add: rp[0..n-1] += s1p[0..n-1] * limb; return carry (high limb) */

640640

static inline mp_limb

641-

limb_addmul_1(mp_limb *rp, const mp_limb *s1p, size_t n, mp_limb limb)

641+

mpn_addmul_1(mp_limb *rp, const mp_limb *s1p, size_t n, mp_limb limb)

642642

{

643643

#if defined(__SIZEOF_INT128__) && (__SIZEOF_INT128__ == 16)

644644

/* Use 128-bit arithmetic with 8x unrolling for maximum efficiency */

@@ -743,6 +743,33 @@ limb_addmul_1(mp_limb *rp, const mp_limb *s1p, size_t n, mp_limb limb)

743743

#endif

744744

}

745745746+

/* Multiply-and-subtract: rp[0..n-1] -= s1p[0..n-1] * limb; return borrow */

747+

static inline mp_limb

748+

mpn_submul_1(mp_limb *rp, const mp_limb *s1p, size_t n, mp_limb limb)

749+

{

750+

mp_dbl_limb borrow = 0;

751+

for (size_t i = 0; i < n; i++) {

752+

mp_dbl_limb prod = (mp_dbl_limb)s1p[i] * (mp_dbl_limb)limb;

753+

mp_dbl_limb sub = (mp_dbl_limb)rp[i] - LOW(prod) - borrow;

754+

rp[i] = LOW(sub);

755+

/* Borrow is 1 if sub underflowed, plus HIGH(prod) */

756+

borrow = HIGH(prod) + (sub >> (sizeof(mp_dbl_limb) * 8 - 1));

757+

}

758+

return (mp_limb)borrow;

759+

}

760+761+

/* Compare two same-length limb arrays: returns <0, 0, or >0 */

762+

static inline int

763+

mpn_cmp(const mp_limb *ap, const mp_limb *bp, size_t n)

764+

{

765+

while (n-- > 0) {

766+

if (ap[n] != bp[n]) {

767+

return (ap[n] > bp[n]) ? 1 : -1;

768+

}

769+

}

770+

return 0;

771+

}

772+746773

#define KARATSUBA_THRESHOLD 32

747774748775

static inline mrb_bool

@@ -751,7 +778,7 @@ should_use_karatsuba(size_t x_len, size_t y_len)

751778

return x_len >= KARATSUBA_THRESHOLD && y_len >= KARATSUBA_THRESHOLD;

752779

}

753780754-

/* w = u * v (optimized schoolbook using limb_addmul_1) */

781+

/* w = u * v (optimized schoolbook using mpn_addmul_1) */

755782

static void

756783

mpz_mul_basic(mpz_ctx_t *ctx, mpz_t *ww, mpz_t *u, mpz_t *v)

757784

{

@@ -774,9 +801,9 @@ mpz_mul_basic(mpz_ctx_t *ctx, mpz_t *ww, mpz_t *u, mpz_t *v)

774801

mp_limb scalar = b->p[0];

775802

mpz_t w;

776803

mpz_init_heap(ctx, &w, a->sz + 1);

777-

limb_zero(w.p, a->sz + 1);

804+

mpn_zero(w.p, a->sz + 1);

778805779-

mp_limb carry = limb_addmul_1(w.p, a->p, a->sz, scalar);

806+

mp_limb carry = mpn_addmul_1(w.p, a->p, a->sz, scalar);

780807

w.p[a->sz] = carry;

781808782809

w.sn = a->sn * b->sn;

@@ -787,13 +814,13 @@ mpz_mul_basic(mpz_ctx_t *ctx, mpz_t *ww, mpz_t *u, mpz_t *v)

787814788815

mpz_t w;

789816

mpz_init_heap(ctx, &w, a->sz + b->sz);

790-

limb_zero(w.p, a->sz + b->sz);

817+

mpn_zero(w.p, a->sz + b->sz);

791818792819

for (size_t j = 0; j < a->sz; j++) {

793820

mp_limb a_limb = a->p[j];

794821

if (a_limb == 0) continue;

795822796-

mp_limb carry = limb_addmul_1(w.p + j, b->p, b->sz, a_limb);

823+

mp_limb carry = mpn_addmul_1(w.p + j, b->p, b->sz, a_limb);

797824798825

/* Properly handle carry propagation to avoid overflow */

799826

size_t k = j + b->sz;

@@ -812,9 +839,9 @@ mpz_mul_basic(mpz_ctx_t *ctx, mpz_t *ww, mpz_t *u, mpz_t *v)

812839813840

/* Allocation-free Karatsuba helper functions */

814841815-

/* Copy limbs: dest[0..n-1] = src[0..n-1] */

842+

/* Copy limbs forward: dest[0..n-1] = src[0..n-1] */

816843

static void

817-

limb_copy(mp_limb *dest, const mp_limb *src, size_t n)

844+

mpn_copyi(mp_limb *dest, const mp_limb *src, size_t n)

818845

{

819846

if (n > 0) {

820847

memcpy(dest, src, n * sizeof(mp_limb));

@@ -857,11 +884,11 @@ static void

857884

mpz_mul_basic_limbs(mp_limb *result, const mp_limb *x, size_t x_len,

858885

const mp_limb *y, size_t y_len)

859886

{

860-

limb_zero(result, x_len + y_len);

887+

mpn_zero(result, x_len + y_len);

861888862889

for (size_t i = 0; i < x_len; i++) {

863890

if (x[i] == 0) continue;

864-

mp_limb carry = limb_addmul_1(result + i, y, y_len, x[i]);

891+

mp_limb carry = mpn_addmul_1(result + i, y, y_len, x[i]);

865892

if (i + y_len < x_len + y_len) {

866893

result[i + y_len] += carry;

867894

}

@@ -886,7 +913,7 @@ static void

886913

mpz_sqr_basic_limbs(mp_limb *result, const mp_limb *x, size_t n)

887914

{

888915

size_t result_len = 2 * n;

889-

limb_zero(result, result_len);

916+

mpn_zero(result, result_len);

890917891918

/* Step 1: Compute off-diagonal terms xi * xj for i < j */

892919

for (size_t i = 0; i < n; i++) {

@@ -895,7 +922,7 @@ mpz_sqr_basic_limbs(mp_limb *result, const mp_limb *x, size_t n)

895922896923

if (i + 1 < n) {

897924

/* Compute xi * x[i+1..n-1] and add at position 2*i+1 */

898-

mp_limb carry = limb_addmul_1(result + 2*i + 1, x + i + 1, n - i - 1, xi);

925+

mp_limb carry = mpn_addmul_1(result + 2*i + 1, x + i + 1, n - i - 1, xi);

899926900927

/* Propagate carry */

901928

size_t k = 2*i + 1 + (n - i - 1);

@@ -1064,8 +1091,8 @@ mpz_mul_karatsuba(mpz_ctx_t *ctx, mp_limb *result,

1064109110651092

/* Step 4: Final assembly: result = z0 + z1*B + z2*B^2 */

10661093

size_t result_len = x_len + y_len;

1067-

limb_zero(result, result_len);

1068-

limb_copy(result, z0, z0_len);

1094+

mpn_zero(result, result_len);

1095+

mpn_copyi(result, z0, z0_len);

10691096

limb_add_at(result, result_len, z1, z1_len, half);

10701097

limb_add_at(result, result_len, z2, z2_len, 2 * half);

10711098

}

@@ -1171,8 +1198,8 @@ mpz_sqr_karatsuba(mpz_ctx_t *ctx, mp_limb *result, const mp_limb *x, size_t n,

1171119811721199

/* Step 4: Final assembly: result = z0 + z1*B + z2*B^2 */

11731200

size_t result_len = 2 * n;

1174-

limb_zero(result, result_len);

1175-

limb_copy(result, z0, z0_len);

1201+

mpn_zero(result, result_len);

1202+

mpn_copyi(result, z0, z0_len);

11761203

limb_add_at(result, result_len, z1, z1_len, half);

11771204

limb_add_at(result, result_len, z2, z2_len, 2 * half);

11781205

}

@@ -1938,7 +1965,6 @@ div_limb(mpz_ctx_t *ctx, mpz_t *q, mpz_t *r, mpz_t *x, mp_limb d)

19381965

pool_restore(ctx, pool_state);

19391966

}

194019671941-19421968

static void

19431969

udiv(mpz_ctx_t *ctx, mpz_t *qq, mpz_t *rr, mpz_t *xx, mpz_t *yy)

19441970

{

Read the original on github.com ↗