/*------------------------------------------------------------------------*/ static uint32 get_prime_roots(poly_coeff_t *c, uint32 p, uint32 *roots, mpz_poly_t *tmp_poly) { /* find all nonzero roots of (N' - x^d) mod p, where d is the desired polynomial degree and N' is the transformed version of N modulo p. We throw out roots of zero because a zero root implies p divides the degree or the leading algebraic poly coefficient, and neither of these is allowed in later stages */ uint32 i, high_coeff; mpz_tdiv_r_ui(tmp_poly->coeff[0], c->trans_N, p); if (mpz_cmp_ui(tmp_poly->coeff[0], 0) == 0) { /* when p divides trans_N, only a root of zero exists, so skip this p */ return 0; } for (i = 1; i < c->degree; i++) mpz_set_ui(tmp_poly->coeff[i], 0); tmp_poly->degree = i; mpz_set_ui(tmp_poly->coeff[i], p - 1); return poly_get_zeros(roots, tmp_poly, p, &high_coeff, 0); }
int knuth(int mm,int *epr,mpz_t N,mpz_t D) { double dp, fks, top = -10.0; char found = FALSE; int i, j, bk=0, nk=0, kk, r, p; static int K[]={0,1,2,3,5,6,7,10,11,13,14,15,17,0};// 这些是可能的multiplier epr[0]=1; epr[1]=2; do { kk=K[++nk]; if(kk==0) { kk=K[bk]; found=TRUE;// 把最大的估计值对应的部分再进行一次求素数而不是直接return } mpz_mul_si(D, N, kk); fks=log(2.0)/2.0; r=mpz_tdiv_r_ui(TB, D, 8); if(r==1) fks*=4.0; if(r==5) fks*=2.0; fks-=log((double)kk)/2.0; i=0; j=1; while(j<mm) { p=qsieve->PRIMES[++i]; r=mpz_tdiv_r_ui(TB, D, p); if(qsieve_powmod(r,(p-1)/2,p)<=1) // 求kk*N的前mm个质数,在这些质数下雅可比符号是0或1 { epr[++j]=p; dp=(double)p; if(kk%p==0) fks+=log(dp)/dp; else fks+=2*log(dp)/(dp-1.0);// 每个素数对估价的贡献 } } if(fks>top) { top=fks; bk=nk; // 最大的估价 } } while(!found); return kk; }
int main (int argc, char **argv) { mpz_t dividend; mpz_t quotient, remainder; mpz_t quotient2, remainder2; mpz_t temp; mp_size_t dividend_size; unsigned long divisor; int i; int reps = 10000; gmp_randstate_ptr rands; mpz_t bs; unsigned long bsi, size_range; unsigned long r_rq, r_q, r_r, r; tests_start (); rands = RANDS; mpz_init (bs); if (argc == 2) reps = atoi (argv[1]); mpz_init (dividend); mpz_init (quotient); mpz_init (remainder); mpz_init (quotient2); mpz_init (remainder2); mpz_init (temp); for (i = 0; i < reps; i++) { mpz_urandomb (bs, rands, 32); size_range = mpz_get_ui (bs) % 10 + 2; /* 0..2047 bit operands */ do { mpz_rrandomb (bs, rands, 64); divisor = mpz_get_ui (bs); } while (divisor == 0); mpz_urandomb (bs, rands, size_range); dividend_size = mpz_get_ui (bs); mpz_rrandomb (dividend, rands, dividend_size); mpz_urandomb (bs, rands, 2); bsi = mpz_get_ui (bs); if ((bsi & 1) != 0) mpz_neg (dividend, dividend); /* printf ("%ld\n", SIZ (dividend)); */ r_rq = mpz_tdiv_qr_ui (quotient, remainder, dividend, divisor); r_q = mpz_tdiv_q_ui (quotient2, dividend, divisor); r_r = mpz_tdiv_r_ui (remainder2, dividend, divisor); r = mpz_tdiv_ui (dividend, divisor); /* First determine that the quotients and remainders computed with different functions are equal. */ if (mpz_cmp (quotient, quotient2) != 0) dump_abort ("quotients from mpz_tdiv_qr_ui and mpz_tdiv_q_ui differ", dividend, divisor); if (mpz_cmp (remainder, remainder2) != 0) dump_abort ("remainders from mpz_tdiv_qr_ui and mpz_tdiv_r_ui differ", dividend, divisor); /* Check if the sign of the quotient is correct. */ if (mpz_cmp_ui (quotient, 0) != 0) if ((mpz_cmp_ui (quotient, 0) < 0) != (mpz_cmp_ui (dividend, 0) < 0)) dump_abort ("quotient sign wrong", dividend, divisor); /* Check if the remainder has the same sign as the dividend (quotient rounded towards 0). */ if (mpz_cmp_ui (remainder, 0) != 0) if ((mpz_cmp_ui (remainder, 0) < 0) != (mpz_cmp_ui (dividend, 0) < 0)) dump_abort ("remainder sign wrong", dividend, divisor); mpz_mul_ui (temp, quotient, divisor); mpz_add (temp, temp, remainder); if (mpz_cmp (temp, dividend) != 0) dump_abort ("n mod d != n - [n/d]*d", dividend, divisor); mpz_abs (remainder, remainder); if (mpz_cmp_ui (remainder, divisor) >= 0) dump_abort ("remainder greater than divisor", dividend, divisor); if (mpz_cmp_ui (remainder, r_rq) != 0) dump_abort ("remainder returned from mpz_tdiv_qr_ui is wrong", dividend, divisor); if (mpz_cmp_ui (remainder, r_q) != 0) dump_abort ("remainder returned from mpz_tdiv_q_ui is wrong", dividend, divisor); if (mpz_cmp_ui (remainder, r_r) != 0) dump_abort ("remainder returned from mpz_tdiv_r_ui is wrong", dividend, divisor); if (mpz_cmp_ui (remainder, r) != 0) dump_abort ("remainder returned from mpz_tdiv_ui is wrong", dividend, divisor); } mpz_clear (bs); mpz_clear (dividend); mpz_clear (quotient); mpz_clear (remainder); mpz_clear (quotient2); mpz_clear (remainder2); mpz_clear (temp); tests_end (); exit (0); }