/* A program to test above function*/ int main() { /* Start with the empty list */ lnodeptr head1 = NULL; lnodeptr head2 = NULL; /*create a linked lists 4->3->2->1 */ list_push(&head1, 1); list_push(&head1, 2); list_push(&head1, 3); list_push(&head1, 4); /*create a linked lists 7->6->5->4 */ list_push(&head2, 4); list_push(&head2, 5); list_push(&head2, 6); list_push(&head2, 7); /*create a linked lists 4->3->2->1->7->6->5->4 */ list_add(&head2,head1); list_pop(&head1); list_pop(&head1); list_pop(&head1); list_pop(&head1); list_pop(&head1); list_pop(&head1); list_push(&head2, 8); list_push(&head2, 9); list_push(&head2, 10); list_push(&head2, 11); list_sub(&head1,head2); list_pop(&head1); list_pop(&head1); list_pop(&head1); printf("\n%d",list_length(head2)); printf("\n%d",list_length(head1)); return 0; }
/* Returns in a[0]+a[1]*x+...+a[K-1]*x^(K-1) the remainder of the division of A = a[0]+a[1]*x+...+a[2K-2]*x^(2K-2) by B = b[0]+b[1]*x+...+b[K-1]*x^(K-1)+b[K]*x^K with b[K]=1 *explicit*. (We have A = Q*B + R with deg(Q)=K-2 and deg(R)=K-1.) Assumes invb[0]+invb[1]*x+...+invb[K-2]*x^(K-2) equals Quo(x^(2K-2), B). Assumes K >= 2. Requires 2K-1 + list_mul_mem(K) cells in t. Notations: R = r[0..K-1], A = a[0..2K-2], low(A) = a[0..K-1], high(A) = a[K..2K-2], Q = t[0..K-2] Return non-zero iff an error occurred. */ int PrerevertDivision (listz_t a, listz_t b, listz_t invb, unsigned int K, listz_t t, mpz_t n) { int po2, wrap; listz_t t2 = NULL; #ifdef WRAP wrap = ks_wrapmul_m (K + 1, K + 1, n) <= 2 * K - 1 + list_mul_mem (K); #else wrap = 0; #endif /* Q <- high(high(A) * INVB) with a short product */ for (po2 = K; (po2 & 1) == 0; po2 >>= 1); po2 = (po2 == 1); if (Fermat && po2) { mpz_set_ui (a[2 * K - 1], 0); if (K <= 4 * Fermat) { F_mul (t, a + K, invb, K, DEFAULT, Fermat, t + 2 * K); /* Put Q in T, as we still need high(A) later on */ list_mod (t, t + K - 2, K, n); } else { F_mul (t, a + K, invb, K, DEFAULT, Fermat, t + 2 * K); list_mod (a + K, t + K - 2, K, n); } } else /* non-Fermat case */ { list_mul_high (t, a + K, invb, K - 1, t + 2 * K - 3); /* the high part of A * INVB is now in {t+K-2, K-1} */ if (wrap) { MEMORY_TAG; t2 = init_list2 (K - 1, mpz_sizeinbase (n, 2)); MEMORY_UNTAG; if (t2 == NULL) { fprintf (ECM_STDERR, "Error, not enough memory\n"); return ECM_ERROR; } list_mod (t2, t + K - 2, K - 1, n); } else /* we can store in high(A) which is no longer needed */ list_mod (a + K, t + K - 2, K - 1, n); } /* the quotient Q = trunc(A / B) has degree K-2, i.e. K-1 terms */ /* T <- low(Q * B) with a short product */ mpz_set_ui (a[2 * K - 1], 0); if (Fermat && po2) { if (K <= 4 * Fermat) { /* Multiply without zero padding, result is (mod x^K - 1) */ F_mul (t + K, t, b, K, NOPAD, Fermat, t + 2 * K); /* Take the leading monomial x^K of B into account */ list_add (t, t + K, t, K); /* Subtract high(A) */ list_sub(t, t, a + K, K); } else F_mul (t, a + K, b, K, DEFAULT, Fermat, t + 2 * K); } else /* non-Fermat case */ { #ifdef KS_MULTIPLY /* ks is faster */ if (wrap) /* Q = {t2, K-1}, B = {b, K+1} We know that Q*B vanishes with the coefficients of degree K to 2K-2 of {A, 2K-1} */ { unsigned int m; m = ks_wrapmul (t, K + 1, b, K + 1, t2, K - 1, n); clear_list (t2, K - 1); /* coefficients of degree m..2K-2 wrap around, i.e. were subtracted to 0..2K-2-m */ if (m < 2 * K - 1) /* otherwise product is exact */ list_add (t, t, a + m, 2 * K - 1 - m); } else LIST_MULT_N (t, a + K, b, K, t + 2 * K - 1); #else list_mul_low (t, a + K, b, K, t + 2 * K - 1, n); #endif } /* now {t, K} contains the low K terms from Q*B */ list_sub (a, a, t, K); list_mod (a, a, K, n); return 0; }
/* 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); } }
/* Puts in a[0..2K-2] the product of b[0..K-1] and c[0..K-1]. The auxiliary memory M(K) necessary in T satisfies: M(1)=0, M(K) = max(3*l-1,2*l-2+M(l)) <= 2*K-1 where l = ceil(K/2). Assumes K >= 1. */ void karatsuba (listz_t a, listz_t b, listz_t c, unsigned int K, listz_t t) { if (K == 1) { mpz_mul (a[0], b[0], c[0]); } else if (K == 2) /* basic Karatsuba scheme */ { mpz_add (t[0], b[0], b[1]); /* t0 = b_0 + b_1 */ mpz_add (a[1], c[0], c[1]); /* a1 = c_0 + c_1 */ mpz_mul (a[1], a[1], t[0]); /* a1 = b_0*c_0 + b_0*c_1 + b_1*c_0 + b_1*c_1 */ mpz_mul (a[0], b[0], c[0]); /* a0 = b_0 * c_0 */ mpz_mul (a[2], b[1], c[1]); /* a2 = b_1 * c_1 */ mpz_sub (a[1], a[1], a[0]); /* a1 = b_0*c_1 + b_1*c_0 + b_1*c_1 */ mpz_sub (a[1], a[1], a[2]); /* a1 = b_0*c_1 + b_1*c_0 */ } else if (K == 3) { /* implement Weimerskirch/Paar trick in 6 muls and 13 adds http://www.crypto.ruhr-uni-bochum.de/Publikationen/texte/kaweb.pdf */ /* diagonal terms */ mpz_mul (a[0], b[0], c[0]); mpz_mul (a[2], b[1], c[1]); mpz_mul (a[4], b[2], c[2]); /* (0,1) rectangular term */ mpz_add (t[0], b[0], b[1]); mpz_add (t[1], c[0], c[1]); mpz_mul (a[1], t[0], t[1]); mpz_sub (a[1], a[1], a[0]); mpz_sub (a[1], a[1], a[2]); /* (1,2) rectangular term */ mpz_add (t[0], b[1], b[2]); mpz_add (t[1], c[1], c[2]); mpz_mul (a[3], t[0], t[1]); mpz_sub (a[3], a[3], a[2]); mpz_sub (a[3], a[3], a[4]); /* (0,2) rectangular term */ mpz_add (t[0], b[0], b[2]); mpz_add (t[1], c[0], c[2]); mpz_mul (t[2], t[0], t[1]); mpz_sub (t[2], t[2], a[0]); mpz_sub (t[2], t[2], a[4]); mpz_add (a[2], a[2], t[2]); } else { unsigned int i, k, l; listz_t z; k = K / 2; l = K - k; z = t + 2 * l - 1; /* improved code with 7*k-3 additions, contributed by Philip McLaughlin <*****@*****.**> */ for (i = 0; i < k; i++) { mpz_sub (z[i], b[i], b[l+i]); mpz_sub (a[i], c[i], c[l+i]); } if (l > k) /* case K odd */ { mpz_set (z[k], b[k]); mpz_set (a[k], c[k]); } /* as b[0..l-1] + b[l..K-1] is stored in t[2l-1..3l-2], we need here at least 3l-1 entries in t */ karatsuba (t, z, a, l, a + l); /* fills t[0..2l-2] */ /* trick: save t[2l-2] in a[2l-1] to enable M(K) <= 2*K-1 */ z = t + 2 * l - 2; mpz_set (a[2*l-1], t[2*l-2]); karatsuba (a, b, c, l, z); /* fill a[0..2l-2] */ karatsuba (a + 2 * l, b + l, c + l, k, z); /* fills a[2l..2K-2] */ mpz_set (t[2*l-2], a[2*l-1]); /* restore t[2*l-2] */ mpz_set_ui (a[2*l-1], 0); /* l l-1 1 l 2k-1-l _________________________________________________ | a0 | a1 |0| a2 | a3 | ------------------------------------------------- l l-1 ________________________ | t0 | t1 | ------------------------ We want to replace [a1, a2] by [a1 + a0 + a2 - t0, a2 + a1 + a3 - t1] i.e. [a12 + a0 - t0, a12 + a3 - t1] where a12 = a1 + a2. */ list_add (a + 2 * l, a + 2 * l, a + l, l-1); /* a[2l..3l-1] <- a1+a2 */ if (k > 1) { list_add (a + l, a + 2 * l, a, l); /* a[l..2l-1] <- a0 + a1 + a2 */ list_add (a + 2 * l, a + 2 * l, a + 3 * l, 2 * k - 1 - l); } else /* k=1, i.e. K=2 or K=3, and a2 has only one entry */ { mpz_add (a[l], a[2*l], a[0]); if (K == 3) mpz_set (a[l+1], a[1]); } list_sub (a + l, a + l, t, 2 * l - 1); } }
/* add or subtract something to/from a list */ int list_addsub(int p, char* list, char* who, int addsub) { struct player *pp = &player_globals.parray[p]; int p1, connected, loadme, personal, ch; char *listname, *member, junkChar; struct List *gl; char *yourthe, *addrem; gl = list_findpartial(p, list, addsub); if (!gl) return COM_OK; personal = ListArray[gl->which].rights == P_PERSONAL; loadme = (gl->which != L_FILTER) && (gl->which != L_REMOVEDCOM) && (gl->which != L_CHANNEL); listname = ListArray[gl->which].name; yourthe = personal ? "your" : "the"; addrem = (addsub == 1) ? "added to" : "removed from"; if (loadme) { if (!FindPlayer(p, who, &p1, &connected)) { if (addsub == 1) return COM_OK; member = who; /* allow sub removed/renamed player */ loadme = 0; } else member = player_globals.parray[p1].name; } else { member = who; } if (addsub == 1) { /* add to list */ if (gl->which == L_CHANNEL) { if (sscanf (who,"%d%c",&ch, &junkChar) == 1 && ch >= 0 && ch < 255) { if ((ch == 0) && (!in_list(p,L_ADMIN,pp->name))) { pprintf(p, "Only admins may join channel 0.\n"); return COM_OK; } } else { pprintf (p,"The channel to add must be a number between 0 and %d.\n",MAX_CHANNELS - 1); return COM_OK; } } if (in_list(p, gl->which, member)) { pprintf(p, "[%s] is already on %s %s list.\n", member, yourthe, listname); if (loadme && !connected) player_remove(p1); return COM_OK; } if (list_add(p, gl->which, member)) { pprintf(p, "Sorry, %s %s list is full.\n", yourthe, listname); if (loadme && !connected) player_remove(p1); return COM_OK; } } else if (addsub == 2) { /* subtract from list */ if (!in_list(p, gl->which, member)) { pprintf(p, "[%s] is not in %s %s list.\n", member, yourthe, listname); if (loadme && !connected) player_remove(p1); return COM_OK; } list_sub(p, gl->which, member); } pprintf(p, "[%s] %s %s %s list.\n", member, addrem, yourthe, listname); if (!personal) { FILE *fp; char filename[MAX_FILENAME_SIZE]; switch (gl->which) { case L_MUZZLE: case L_CMUZZLE: case L_C1MUZZLE: case L_C24MUZZLE: case L_C46MUZZLE: case L_C49MUZZLE: case L_C50MUZZLE: case L_C51MUZZLE: case L_ABUSER: case L_BAN: case L_NOTEBAN: case L_RATEBAN: pprintf(p, "Please leave a comment to explain why %s was %s the %s list.\n", member, addrem, listname); pcommand(p, "addcomment %s %s %s list.\n", member, addrem, listname); break; case L_COMPUTER: /*if (player_globals.parray[p1].z_stats.rating > 0) UpdateRank(TYPE_CRAZYHOUSE, member, &player_globals.parray[p1].z_stats, member); if (player_globals.parray[p1].s_stats.rating > 0) UpdateRank(TYPE_STAND, member, &player_globals.parray[p1].s_stats, member); if (player_globals.parray[p1].w_stats.rating > 0) UpdateRank(TYPE_WILD, member, &player_globals.parray[p1].w_stats, member);*/ break; case L_ADMIN: if (addsub == 1) { /* adding to list */ player_globals.parray[p1].adminLevel = 10; pprintf(p, "%s has been given an admin level of 10 - change with asetadmin.\n", member); } else { player_globals.parray[p1].adminLevel = 0; } break; case L_FILTER: case L_REMOVEDCOM: default: break; } if (loadme && connected) pprintf_prompt(p1, "You have been %s the %s list by %s.\n", addrem, listname, pp->name); sprintf(filename, "%s/%s", LISTS_DIR, listname); fp = fopen_s(filename, "w"); if (fp == NULL) { d_printf( "Couldn't save %s list.\n", listname); } else { int i; for (i = 0; i < gl->numMembers; i++) fprintf(fp, "%s\n", gl->m_member[i]); fclose(fp); } } if (loadme || (gl->which == L_ADMIN)) { player_save(p1); } if (loadme && !connected) { player_remove(p1); } return COM_OK; }