#include "ulong_extras.h"
#include "factor_tables.h"
static int n_is_oddprime_small2(ulong n)
{
ulong q = n / 2;
ulong x = (q & 63);
return (flint_odd_prime_lookup[q / 64] & (((uint64_t) 1) << x)) >> x;
}
#define APPEND_FACTOR(prime, exponent) \
do \
{ \
fac->p[fac->num] = (prime); \
fac->exp[fac->num] = (exponent); \
fac->num++; \
} while (0)
#define REMOVE_ODD_TRIAL_PRIME(i) \
do { \
ulong inv1 = flint_trial_primes_inv1[i]; \
ulong inv2 = flint_trial_primes_inv2[i]; \
if (n_divisible_odd_gm(x, inv1, inv2)) \
{ \
exp = 1; \
x *= inv1; \
while ((n_divisible_odd_gm(x, inv1, inv2))) \
{ \
exp++; \
x *= inv1; \
} \
APPEND_FACTOR(flint_trial_primes[i], exp); \
if (x == 1) \
return; \
if (x < SMALL_ODDPRIME_LIMIT && n_is_oddprime_small2(x)) \
{ \
APPEND_FACTOR(x, 1); \
return; \
} \
} \
} while (0)
#define USE_PP1 0
static
ulong n_factor_composite_after_trial(ulong n)
{
ulong f;
if (n > FLINT_FACTOR_POLLARD_BRENT_MIN)
if (n_factor_pollard_brent_single(&f, n, 1, 1, FLINT_FACTOR_POLLARD_BRENT_ITERS) == 1)
return f;
#if FLINT64
if (n < FLINT_FACTOR_ONE_LINE_MAX)
if ((f = n_factor_one_line(n, FLINT_FACTOR_ONE_LINE_ITERS)))
return f;
#endif
#if USE_PP1
if ((f = n_factor_pp1_wrapper2(n)))
return f;
#endif
if ((f = n_factor_SQUFOF(n, FLINT_FACTOR_SQUFOF_ITERS)))
return f;
flint_throw(FLINT_ERROR, "Exception (n_factor). Failed to factor %wu.\n", n);
}
static void n_factor_after_trial(n_factor_t * factors, ulong n, ulong cutoff)
{
ulong factor_arr[FLINT_MAX_FACTORS_IN_LIMB];
ulong exp_arr[FLINT_MAX_FACTORS_IN_LIMB];
ulong factors_left;
ulong exp;
ulong cofactor, factor;
if (n == 1)
return;
if (n_is_prime_odd_no_trial(n))
{
n_factor_insert(factors, n, 1);
return;
}
cofactor = n;
factor_arr[0] = cofactor;
factors_left = 1;
exp_arr[0] = 1;
while (factors_left > 0)
{
factor = factor_arr[factors_left - 1];
if (factor >= cutoff)
{
if ((cofactor = n_factor_power235(&exp, factor)))
{
exp_arr[factors_left - 1] *= exp;
factor_arr[factors_left - 1] = factor = cofactor;
}
if (factor < cutoff || (factor != n && n_is_prime_odd_no_trial(factor)))
{
n_factor_insert(factors, factor, exp_arr[factors_left - 1]);
factors_left--;
}
else
{
cofactor = n_factor_composite_after_trial(factor);
exp_arr[factors_left] = exp_arr[factors_left - 1];
factor_arr[factors_left] = cofactor;
factor_arr[factors_left - 1] /= cofactor;
factors_left++;
}
}
else
{
n_factor_insert(factors, factor, exp_arr[factors_left - 1]);
factors_left--;
}
}
}
void
n_factor(n_factor_t * fac, ulong x, int FLINT_UNUSED(proved))
{
slong i, exp;
fac->num = 0;
if (x <= 1)
return;
if (x % 2 == 0)
{
exp = flint_ctz(x);
x >>= exp;
APPEND_FACTOR(2, exp);
if (x == 1)
return;
}
if (x < SMALL_ODDPRIME_LIMIT && n_is_oddprime_small2(x))
{
APPEND_FACTOR(x, 1);
return;
}
FLINT_ASSERT(FLINT_FACTOR_TRIAL_PRIMES_BEFORE_PRIMALITY_TEST % 2 == 0);
FLINT_ASSERT(FLINT_FACTOR_TRIAL_PRIMES % 2 == 0);
i = 1;
if (x % 3 == 0)
REMOVE_ODD_TRIAL_PRIME(1);
for (i = 2; i < FLINT_FACTOR_TRIAL_PRIMES_BEFORE_PRIMALITY_TEST; i += 2)
{
REMOVE_ODD_TRIAL_PRIME(i);
REMOVE_ODD_TRIAL_PRIME(i + 1);
if (x <= (ulong) flint_trial_primes[i+1] * (ulong) flint_trial_primes[i+1])
{
APPEND_FACTOR(x, 1);
return;
}
}
if (n_is_prime_odd_no_trial(x))
{
APPEND_FACTOR(x, 1);
return;
}
for ( ; i < FLINT_FACTOR_TRIAL_PRIMES; i += 2)
{
REMOVE_ODD_TRIAL_PRIME(i);
REMOVE_ODD_TRIAL_PRIME(i + 1);
if (x <= (ulong) flint_trial_primes[i+1] * (ulong) flint_trial_primes[i+1])
{
APPEND_FACTOR(x, 1);
return;
}
}
n_factor_after_trial(fac, x, FLINT_FACTOR_TRIAL_CUTOFF);
}