/* Multiplies b[0..k-1] by c[0..k-1], stores the result in a[0..2k-2], and stores the reduced product in a2[0..2k-2]. (Here, there is no implicit monic leading monomial.) Requires at least list_mul_mem(k) cells in t. */ void list_mulmod (listz_t a2, listz_t a, listz_t b, listz_t c, unsigned int k, listz_t t, mpz_t n) { int i; for (i = k; (i & 1) == 0; i >>= 1); ASSERTD(list_check(b,k,n)); ASSERTD(list_check(c,k,n)); if (i == 1 && Fermat) F_mul (a, b, c, k, DEFAULT, Fermat, t); else LIST_MULT_N (a, b, c, k, t); /* set a[0]...a[2l-2] */ list_mod (a2, a, 2 * k - 1, n); }
/* puts in a[0]..a[K-1] the K low terms of the product of b[0..K-1] and c[0..K-1]. Assumes K >= 1, and a[0..2K-2] exist. Needs space for list_mul_mem(K) in t. */ static void list_mul_low (listz_t a, listz_t b, listz_t c, unsigned int K, listz_t t, mpz_t n) { unsigned int p, q; ASSERT(K > 0); switch (K) { case 1: mpz_mul (a[0], b[0], c[0]); return; case 2: mpz_mul (a[0], b[0], c[0]); mpz_mul (a[1], b[0], c[1]); mpz_addmul (a[1], b[1], c[0]); return; case 3: karatsuba (a, b, c, 2, t); mpz_addmul (a[2], b[2], c[0]); mpz_addmul (a[2], b[0], c[2]); return; default: /* MULT is 2 for Karatsuba, 3 for Toom3, 4 for Toom4 */ for (p = 1; MULT * p <= K; p *= MULT); /* p = greatest power of MULT <=K */ p = (K / p) * p; ASSERTD(list_check(b,p,n) && list_check(c,p,n)); LIST_MULT_N (a, b, c, p, t); if ((q = K - p)) { list_mul_low (t, b + p, c, q, t + 2 * q - 1, n); list_add (a + p, a + p, t, q); list_mul_low (t, c + p, b, q, t + 2 * q - 1, n); list_add (a + p, a + p, t, q); } } }
/* divides a[0]+a[1]*x+...+a[2K-1]*x^(2K-1) By b[0]+b[1]*x+...+b[K-1]*x^(K-1)+x^K i.e. a polynomial of 2K coefficients divided by a monic polynomial with K+1 coefficients (b[K]=1 is implicit). Puts the quotient in q[0]+q[1]*x+...+q[K-1]*x^(K-1) and the remainder in a[0]+a[1]*x+...+a[K-1]*x^(K-1) Needs space for list_mul_mem(K) coefficients in t. If top is non-zero, a[0]..a[K-1] are reduced mod n. */ void RecursiveDivision (listz_t q, listz_t a, listz_t b, unsigned int K, listz_t t, mpz_t n, int top) { if (K == 1) /* a0+a1*x = a1*(b0+x) + a0-a1*b0 */ { mpz_mod (a[1], a[1], n); mpz_mul (q[0], a[1], b[0]); mpz_mod (q[0], q[0], n); mpz_sub (a[0], a[0], q[0]); if (top) mpz_mod (a[0], a[0], n); mpz_set (q[0], a[1]); } else { unsigned int k, l, i, po2; k = K / 2; l = K - k; for (po2 = K; (po2 && 1) == 0; po2 >>= 1); po2 = (po2 == 1); /* first perform a (2l) / l division */ RecursiveDivision (q + k, a + 2 * k, b + k, l, t, n, 0); /* subtract q[k..k+l-1] * b[0..k-1] */ ASSERTD(list_check(q+l,k,n) && list_check(b,k,n)); if (po2 && Fermat) F_mul (t, q + l, b, k, DEFAULT, Fermat, t + K); /* sets t[0..2*k-2]*/ else LIST_MULT_N (t, q + l, b, k, t + K - 1); /* sets t[0..2*k-2] */ list_sub (a + l, a + l, t, 2 * k - 1); if (k < l) /* don't forget to subtract q[k] * b[0..k-1] */ { for (i=0; i<k; i++) { mpz_mul (t[0], q[k], b[i]); /* TODO: need to reduce t[0]? */ mpz_sub (a[k+i], a[k+i], t[0]); } } /* remainder is in a[0..K+k-1] */ /* then perform a (2k) / k division */ RecursiveDivision (q, a + l, b + l, k, t, n, 0); /* subtract q[0..k-1] * b[0..l-1] */ ASSERTD(list_check(q,k,n) && list_check(b,k,n)); if (po2 && Fermat) F_mul (t, q, b, k, DEFAULT, Fermat, t + K); else LIST_MULT_N (t, q, b, k, t + K - 1); list_sub (a, a, t, 2 * k - 1); if (k < l) /* don't forget to subtract q[0..k-1] * b[k] */ { for (i=0; i<k; i++) { mpz_mul (t[0], q[i], b[k]); /* TODO: need to reduce t[0]? */ mpz_sub (a[k+i], a[k+i], t[0]); } } /* normalizes the remainder wrt n */ if (top) list_mod (a, a, K, n); } }
/* puts in q[0..K-1] the quotient of x^(2K-2) by B where B = b[0]+b[1]*x+...+b[K-1]*x^(K-1) with b[K-1]=1. */ void PolyInvert (listz_t q, listz_t b, unsigned int K, listz_t t, mpz_t n) { if (K == 1) { mpz_set_ui (q[0], 1); return; } else { int k, l, po2, use_middle_product = 0; #ifdef KS_MULTIPLY use_middle_product = 1; #endif k = K / 2; l = K - k; for (po2 = K; (po2 & 1) == 0; po2 >>= 1); po2 = (po2 == 1 && Fermat != 0); /* first determine l most-significant coeffs of Q */ PolyInvert (q + k, b + k, l, t, n); /* Q1 = {q+k, l} */ /* now Q1 * B = x^(2K-2) + O(x^(2K-2-l)) = x^(2K-2) + O(x^(K+k-2)). We need the coefficients of degree K-1 to K+k-2 of Q1*B */ ASSERTD(list_check(q+k,l,n) && list_check(b,l,n)); if (po2 == 0 && use_middle_product) { TMulKS (t, k - 1, q + k, l - 1, b, K - 1, n, 0); list_neg (t, t, k, n); } else if (po2) { list_revert (q + k, l); /* This expects the leading monomials explicitly in q[2k-1] and b[k+l-1] */ F_mul_trans (t, q + k, b, K / 2, K, Fermat, t + k); list_revert (q + k, l); list_neg (t, t, k, n); } else { LIST_MULT_N (t, q + k, b, l, t + 2 * l - 1); /* t[0..2l-1] = Q1 * B0 */ list_neg (t, t + l - 1, k, n); if (k > 1) { list_mul (t + k, q + k, l - 1, 1, b + l, k - 1, 1, t + k + K - 2); /* Q1 * B1 */ list_sub (t + 1, t + 1, t + k, k - 1); } } list_mod (t, t, k, n); /* high(1-B*Q1) */ ASSERTD(list_check(t,k,n) && list_check(q+l,k,n)); if (po2) F_mul (t + k, t, q + l, k, DEFAULT, Fermat, t + 3 * k); else LIST_MULT_N (t + k, t, q + l, k, t + 3 * k - 1); list_mod (q, t + 2 * k - 1, k, n); } }
void TestParser::endNode() { ASSERTD( isNotNullP( curr_node)); curr_node->doc()->setPlainText( node_text); }