/*------------------------------------------------------------------------*/
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);
}