void mpn_mullow_n (mp_ptr rp, mp_srcptr xp, mp_srcptr yp, mp_size_t n) { if (BELOW_THRESHOLD (n, MULLOW_BASECASE_THRESHOLD)) { /* Allocate workspace of fixed size on stack: fast! */ mp_limb_t ws[MUL_BASECASE_ALLOC]; mpn_mul_basecase (ws, xp, n, yp, n); MPN_COPY (rp, ws, n); } else if (BELOW_THRESHOLD (n, MULLOW_DC_THRESHOLD)) { mpn_mullow_basecase (rp, xp, yp, n); } else if (BELOW_THRESHOLD (n, MULLOW_MUL_N_THRESHOLD)) { /* Divide-and-conquer */ mp_size_t n2 = n >> 1; /* floor(n/2) */ mp_size_t n1 = n - n2; /* ceil(n/2) */ mp_ptr tp; TMP_SDECL; TMP_SMARK; tp = TMP_SALLOC_LIMBS (n1); /* Split as x = x1 2^(n1 GMP_NUMB_BITS) + x0, y = y1 2^(n2 GMP_NUMB_BITS) + y0 */ /* x0 * y0 */ mpn_mul_n (rp, xp, yp, n2); if (n1 != n2) rp[2 * n2] = mpn_addmul_1 (rp + n2, yp, n2, xp[n2]); /* x1 * y0 * 2^(n1 GMP_NUMB_BITS) */ mpn_mullow_n (tp, xp + n1, yp, n2); mpn_add_n (rp + n1, rp + n1, tp, n2); /* x0 * y1 * 2^(n2 GMP_NUMB_BITS) */ mpn_mullow_n (tp, yp + n2, xp, n1); mpn_add_n (rp + n2, rp + n2, tp, n1); TMP_SFREE; } else {
void mpn_binvert (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_ptr scratch) { mp_ptr xp; mp_size_t rn, newrn; mp_size_t sizes[NPOWS], *sizp; mp_limb_t di; /* Compute the computation precisions from highest to lowest, leaving the base case size in 'rn'. */ sizp = sizes; for (rn = n; ABOVE_THRESHOLD (rn, BINV_NEWTON_THRESHOLD); rn = (rn + 1) >> 1) *sizp++ = rn; xp = scratch; /* Compute a base value using a low-overhead O(n^2) algorithm. FIXME: We should call some divide-and-conquer lsb division function here for an operand subrange. */ MPN_ZERO (xp, rn); xp[0] = 1; binvert_limb (di, up[0]); if (BELOW_THRESHOLD (rn, DC_BDIV_Q_THRESHOLD)) mpn_sb_bdiv_q (rp, xp, rn, up, rn, -di); else mpn_dc_bdiv_q (rp, xp, rn, up, rn, -di); /* Use Newton iterations to get the desired precision. */ for (; rn < n; rn = newrn) { newrn = *--sizp; #if WANT_FFT if (ABOVE_THRESHOLD (newrn, 2 * MUL_FFT_MODF_THRESHOLD)) { int k; mp_size_t m, i; k = mpn_fft_best_k (newrn, 0); m = mpn_fft_next_size (newrn, k); mpn_mul_fft (xp, m, up, newrn, rp, rn, k); for (i = rn - 1; i >= 0; i--) if (xp[i] > (i == 0)) { mpn_add_1 (xp + rn, xp + rn, newrn - rn, 1); break; } } else #endif mpn_mul (xp, up, newrn, rp, rn); mpn_mullow_n (rp + rn, rp, xp + rn, newrn - rn); mpn_neg_n (rp + rn, rp + rn, newrn - rn); } }
int main (void) { unsigned long bp, xn, n, b, zn, c; mp_limb_t xp[1000], yp[1000], mp[1000], lp[1000], hp[1000]; gmp_randstate_t rands; int qpn, j, k, i, l, i1, k1, j1, i2, k2, j2; tests_start (); gmp_randinit_default(rands); for (n = 1; n < 100; n++) { for (c = 0; c < 10; c++) { mpn_randomb (xp, rands, n); mpn_randomb (yp, rands, n); mpn_mul_n (mp, xp, yp, n); mpn_mullow_n (lp, xp, yp, n); mpn_mulhigh_n (hp, xp, yp, n); if (mpn_cmp (mp, lp, n) != 0) { printf ("mpn_mullow_n error %ld\n", n); abort (); } if (mpn_cmp (mp + n, hp + n, n) != 0) { printf ("mpn_mulhigh_n error %ld\n", n); abort (); } } } gmp_randclear(rands); tests_end (); exit (0); }