#include <math.h>
#include "ulong_extras.h"
#include "fmpz.h"
#include "qsieve.h"
static const ulong multipliers[] = {1, 2, 3, 5, 6, 7, 10, 11, 13, 14, 15,
17, 19, 21, 22, 23, 26, 29, 30, 31,
33, 34, 35, 37, 38, 41, 42, 43, 47};
#define KS_MULTIPLIERS (sizeof(multipliers)/sizeof(ulong))
ulong qsieve_knuth_schroeppel(qs_t qs_inf)
{
float weights[KS_MULTIPLIERS];
float best_weight = -10.0f;
ulong i, num_primes, max;
float logpdivp;
ulong nmod8, mod8, p, nmod, pinv, mult;
int kron, jac;
n_primes_t iter;
if (fmpz_is_even(qs_inf->n))
return 2;
nmod8 = fmpz_fdiv_ui(qs_inf->n, 8);
for (i = 0; i < KS_MULTIPLIERS; i++)
{
mod8 = ((nmod8*multipliers[i]) % 8);
weights[i] = 0.34657359;
if (mod8 == 1) weights[i] *= 4.0;
if (mod8 == 5) weights[i] *= 2.0;
weights[i] -= (log((float) multipliers[i]) / 2.0);
}
max = FLINT_MIN(qs_inf->ks_primes, qs_inf->num_primes - 3);
n_primes_init(iter);
n_primes_next(iter);
p = n_primes_next(iter);
for (num_primes = 0; num_primes < max; num_primes++)
{
pinv = n_preinvert_limb(p);
logpdivp = log((float) p) / (float) p;
nmod = fmpz_fdiv_ui(qs_inf->n, p);
if (nmod == 0) return p;
kron = 1;
while (nmod % 2 == 0)
{
if (p % 8 == 3 || p % 8 == 5) kron *= -1;
nmod /= 2;
}
kron *= n_jacobi(nmod, p);
for (i = 0; i < KS_MULTIPLIERS; i++)
{
mult = multipliers[i];
if (mult >= p)
mult = n_mod2_preinv(mult, p, pinv);
if (mult == 0) weights[i] += logpdivp;
else
{
jac = 1;
while (mult % 2 == 0)
{
if (p % 8 == 3 || p % 8 == 5) jac *= -1;
mult /= 2;
}
if (kron*jac*n_jacobi(mult, p) == 1)
weights[i] += 2.0*logpdivp;
}
}
p = n_primes_next(iter);
}
n_primes_clear(iter);
for (i = 0; i < KS_MULTIPLIERS; i++)
{
if (weights[i] > best_weight)
{
best_weight = weights[i];
qs_inf->k = multipliers[i];
}
}
#if QS_DEBUG
flint_printf("Using Knuth-Schroeppel multiplier %wd\n", qs_inf->k);
#endif
return 0;
}