#include "pari.h"
#include "paripriv.h"
#define NPRC 128
static unsigned char prc210_no[] = {
0, NPRC, NPRC, NPRC, NPRC, 1, 2, NPRC, 3, 4, NPRC,
5, NPRC, NPRC, 6, 7, NPRC, NPRC, 8, NPRC, 9,
10, NPRC, 11, NPRC, NPRC, 12, NPRC, NPRC, 13, 14, NPRC,
NPRC, 15, NPRC, 16, 17, NPRC, NPRC, 18, NPRC, 19,
NPRC, NPRC, 20, NPRC, NPRC, NPRC, 21, NPRC, 22, 23, NPRC,
24, 25, NPRC, 26, NPRC, NPRC, NPRC, 27, NPRC, NPRC,
28, NPRC, 29, NPRC, NPRC, 30, 31, NPRC, 32, NPRC, NPRC,
33, 34, NPRC, NPRC, 35, NPRC, NPRC, 36, NPRC, 37,
38, NPRC, 39, NPRC, NPRC, 40, 41, NPRC, NPRC, 42, NPRC,
43, 44, NPRC, 45, 46, NPRC, NPRC, NPRC, NPRC, 47,
};
static unsigned char prc210_d1[] = {
10, 2, 4, 2, 4, 6, 2, 6, 4, 2, 4, 6, 6, 2, 6, 4, 2, 6,
4, 6, 8, 4, 2, 4, 2, 4, 8, 6, 4, 6, 2, 4, 6,
2, 6, 6, 4, 2, 4, 6, 2, 6, 4, 2, 4, 2, 10, 2,
};
ulong
unextprime(ulong n)
{
long rc, rc0, rcd, rcn;
switch(n) {
case 0: case 1: case 2: return 2;
case 3: return 3;
case 4: case 5: return 5;
case 6: case 7: return 7;
}
#ifdef LONG_IS_64BIT
if (n > (ulong)-59) return 0;
#else
if (n > (ulong)-5) return 0;
#endif
n |= 1;
rc = rc0 = n % 210;
for(;;)
{
rcn = (long)(prc210_no[rc>>1]);
if (rcn != NPRC) break;
rc += 2;
}
if (rc > rc0) n += rc - rc0;
for(;;)
{
if (uisprime(n)) break;
rcd = prc210_d1[rcn];
if (++rcn > 47) rcn = 0;
n += rcd;
}
return n;
}
GEN
nextprime(GEN n)
{
long rc, rc0, rcd, rcn;
pari_sp av = avma;
if (typ(n) != t_INT)
{
n = gceil(n);
if (typ(n) != t_INT) pari_err_TYPE("nextprime",n);
}
if (signe(n) <= 0) { avma = av; return gen_2; }
if (lgefint(n) == 3)
{
ulong k = unextprime(uel(n,2));
avma = av;
if (k) return utoipos(k);
#ifdef LONG_IS_64BIT
return uutoi(1,13);
#else
return uutoi(1,15);
#endif
}
if (!mod2(n)) n = addui(1,n);
rc = rc0 = umodiu(n, 210);
for(;;)
{
rcn = (long)(prc210_no[rc>>1]);
if (rcn != NPRC) break;
rc += 2;
}
if (rc > rc0) n = addui(rc - rc0, n);
for(;;)
{
if (BPSW_psp(n)) break;
rcd = prc210_d1[rcn];
if (++rcn > 47) rcn = 0;
n = addui(rcd, n);
}
if (avma == av) return icopy(n);
return gerepileuptoint(av, n);
}
ulong
uprecprime(ulong n)
{
long rc, rc0, rcd, rcn;
{
if (n <= 1) return 0;
if (n == 2) return 2;
if (n <= 4) return 3;
if (n <= 6) return 5;
if (n <= 10) return 7;
}
if (!(n % 2)) n--;
rc = rc0 = n % 210;
for(;;)
{
rcn = (long)(prc210_no[rc>>1]);
if (rcn != NPRC) break;
rc -= 2;
}
if (rc < rc0) n += rc - rc0;
for(;;)
{
if (uisprime(n)) break;
if (--rcn < 0) rcn = 47;
rcd = prc210_d1[rcn];
n -= rcd;
}
return n;
}
GEN
precprime(GEN n)
{
long rc, rc0, rcd, rcn;
pari_sp av = avma;
if (typ(n) != t_INT)
{
n = gfloor(n);
if (typ(n) != t_INT) pari_err_TYPE("nextprime",n);
}
if (signe(n) <= 0) { avma = av; return gen_0; }
if (lgefint(n) <= 3)
{
ulong k = uel(n,2);
avma = av;
return utoi(uprecprime(k));
}
if (!mod2(n)) n = subiu(n,1);
rc = rc0 = umodiu(n, 210);
for(;;)
{
rcn = (long)(prc210_no[rc>>1]);
if (rcn != NPRC) break;
rc -= 2;
}
if (rc0 > rc) n = subiu(n, rc0 - rc);
for(;;)
{
if (BPSW_psp(n)) break;
if (--rcn < 0) rcn = 47;
rcd = prc210_d1[rcn];
n = subiu(n, rcd);
}
if (avma == av) return icopy(n);
return gerepileuptoint(av, n);
}
ulong
snextpr(ulong p, byteptr *d, long *rcn, long *q, long k)
{
ulong n;
if (**d)
{
byteptr dd = *d;
long d1 = 0;
NEXT_PRIME_VIADIFF(d1,dd);
if (*rcn != NPRC)
{
while (d1 > 0)
{
d1 -= prc210_d1[*rcn];
if (++*rcn > 47) { *rcn = 0; if (q) (*q)++; }
}
}
NEXT_PRIME_VIADIFF(p,*d);
return p;
}
if (*rcn == NPRC) *rcn = prc210_no[(p % 210) >> 1];
n = p + prc210_d1[*rcn];
if (++*rcn > 47) *rcn = 0;
while (!Fl_MR_Jaeschke(n, k))
{
n += prc210_d1[*rcn];
if (n <= 11) pari_err_OVERFLOW("snextpr");
if (++*rcn > 47) { *rcn = 0; if (q) (*q)++; }
}
return n;
}
int factor_add_primes = 0, factor_proven = 0;
#define nbcmax 64
static const ulong TB1[] = {
142,172,208,252,305,370,450,545,661,801,972,1180,1430,
1735,2100,2550,3090,3745,4540,5505,6675,8090,9810,11900,
14420,17490,21200,25700,31160,37780UL,45810UL,55550UL,67350UL,
81660UL,99010UL,120050UL,145550UL,176475UL,213970UL,259430UL,
314550UL,381380UL,462415UL,560660UL,679780UL,824220UL,999340UL,
1211670UL,1469110UL,1781250UL,2159700UL,2618600UL,3175000UL,
3849600UL,4667500UL,5659200UL,6861600UL,8319500UL,10087100UL,
12230300UL,14828900UL,17979600UL,21799700UL,26431500UL,
32047300UL,38856400UL,
#ifdef LONG_IS_64BIT
47112200UL,57122100UL,69258800UL,83974200UL,101816200UL,
123449000UL,149678200UL,181480300UL,220039400UL,266791100UL,
323476100UL,392204900UL,475536500UL,576573500UL,699077800UL,
847610500UL,1027701900UL,1246057200UL,1510806400UL,1831806700UL,
2221009800UL,2692906700UL,3265067200UL,3958794400UL,4799917500UL
#endif
};
static const ulong TB1_for_stage[] = {
500,520,560,620,700,800,900,1000,1150,1300,1450,1600,1800,2000,
2200,2450,2700,2950,3250,3600,4000,4400,4850,5300,5800,6400,
7100,7850,8700,9600,10600,11700,12900,14200,15700,17300,
19000,21000,23200,25500,28000,31000,34500UL,38500UL,43000UL,
48000UL,53800UL,60400UL,67750UL,76000UL,85300UL,95700UL,
107400UL,120500UL,135400UL,152000UL,170800UL,191800UL,215400UL,
241800UL,271400UL,304500UL,341500UL,383100UL,429700UL,481900UL,
540400UL,606000UL,679500UL,761800UL,854100UL,957500UL,1073500UL
};
static void
FpE_add_i(GEN N, GEN z, GEN Px, GEN Py, GEN Qx, GEN Qy, GEN *Rx, GEN *Ry)
{
GEN slope = modii(mulii(subii(Py, Qy), z), N);
GEN t = subii(sqri(slope), addii(Qx, Px));
affii(modii(t, N), *Rx);
if (Ry) {
t = subii(mulii(slope, subii(Px, *Rx)), Py);
affii(modii(t, N), *Ry);
}
}
static void
ZV_aff(long n, GEN *X, GEN *Z)
{
if (X != Z) {
long k;
for (k = n; k--; ) affii(X[k],Z[k]);
}
}
static int
ecm_elladd0(GEN N, GEN *gl, long nbc, long nbc1,
GEN *X1, GEN *Y1, GEN *X2, GEN *Y2, GEN *X3, GEN *Y3)
{
const ulong mask = (nbc1 == 4)? 3: ~0UL;
GEN W[2*nbcmax], *A = W+nbc;
long i;
pari_sp av = avma;
W[1] = subii(X1[0], X2[0]);
for (i=1; i<nbc; i++)
{
A[i] = subii(X1[i&mask], X2[i]);
W[i+1] = modii(mulii(A[i], W[i]), N);
}
if (!invmod(W[nbc], N, gl))
{
if (!equalii(N,*gl)) return 2;
ZV_aff(nbc, X2,X3);
if (Y3) ZV_aff(nbc, Y2,Y3);
avma = av; return 1;
}
while (i--)
{
pari_sp av2 = avma;
GEN Px = X1[i&mask], Py = Y1[i&mask], Qx = X2[i], Qy = Y2[i];
GEN z = i? mulii(*gl,W[i]): *gl;
FpE_add_i(N,z, Px,Py,Qx,Qy, X3+i, Y3? Y3+i: NULL);
if (!i) break;
avma = av2; *gl = modii(mulii(*gl, A[i]), N);
}
avma = av; return 0;
}
static int
ecm_elladd(GEN N, GEN *gl, long nbc, GEN *X1, GEN *X2, GEN *X3) {
return ecm_elladd0(N, gl, nbc, nbc, X1, X1+nbc, X2, X2+nbc, X3, X3+nbc);
}
static int
ecm_elladd2(GEN N, GEN *gl, long nbc,
GEN *X1, GEN *X2, GEN *X3, GEN *X4, GEN *X5, GEN *X6)
{
GEN *Y1 = X1+nbc, *Y2 = X2+nbc, *Y3 = X3+nbc;
GEN *Y4 = X4+nbc, *Y5 = X5+nbc, *Y6 = X6+nbc;
GEN W[4*nbcmax], *A = W+2*nbc;
long i, j;
pari_sp av = avma;
W[1] = subii(X1[0], X2[0]);
for (i=1; i<nbc; i++)
{
A[i] = subii(X1[i], X2[i]);
W[i+1] = modii(mulii(A[i], W[i]), N);
}
for (j=0; j<nbc; i++,j++)
{
A[i] = subii(X4[j], X5[j]);
W[i+1] = modii(mulii(A[i], W[i]), N);
}
if (!invmod(W[2*nbc], N, gl))
{
if (!equalii(N,*gl)) return 2;
ZV_aff(2*nbc, X2,X3);
ZV_aff(2*nbc, X5,X6);
avma = av; return 1;
}
while (j--)
{
pari_sp av2 = avma;
GEN Px = X4[j], Py = Y4[j], Qx = X5[j], Qy = Y5[j];
GEN z = mulii(*gl,W[--i]);
FpE_add_i(N,z, Px,Py, Qx,Qy, X6+j,Y6+j);
avma = av2; *gl = modii(mulii(*gl, A[i]), N);
}
while (i--)
{
pari_sp av2 = avma;
GEN Px = X1[i], Py = Y1[i], Qx = X2[i], Qy = Y2[i];
GEN z = i? mulii(*gl, W[i]): *gl;
FpE_add_i(N,z, Px,Py, Qx,Qy, X3+i,Y3+i);
if (!i) break;
avma = av2; *gl = modii(mulii(*gl, A[i]), N);
}
avma = av; return 0;
}
static int
elldouble(GEN N, GEN *gl, long nbc, GEN *X1, GEN *X2)
{
GEN *Y1 = X1+nbc, *Y2 = X2+nbc;
GEN W[nbcmax+1];
long i;
pari_sp av = avma;
W[1] = Y1[0];
for (i=1; i<nbc; i++) W[i+1] = modii(mulii(Y1[i], W[i]), N);
if (!invmod(W[nbc], N, gl))
{
if (!equalii(N,*gl)) return 2;
ZV_aff(2*nbc,X1,X2);
avma = av; return 1;
}
while (i--)
{
pari_sp av2;
GEN v, w, L, z = i? mulii(*gl,W[i]): *gl;
if (i) *gl = modii(mulii(*gl, Y1[i]), N);
av2 = avma;
L = modii(mulii(addui(1, mului(3, Fp_sqr(X1[i],N))), z), N);
if (signe(L))
L = shifti(mod2(L)? addii(L, N): L, -1);
v = modii(subii(sqri(L), shifti(X1[i],1)), N);
w = modii(subii(mulii(L, subii(X1[i], v)), Y1[i]), N);
affii(v, X2[i]);
affii(w, Y2[i]);
avma = av2;
}
avma = av; return 0;
}
static int
get_rule(ulong d, ulong e)
{
if (d <= e + (e>>2))
{
if ((d+e)%3 == 0) return 0;
if ((d-e)%6 == 0) return 1;
}
if ((d+3)>>2 <= e) return 2;
if ((d&1)==(e&1)) return 1;
if (!(d&1)) return 3;
if (d%3 == 0) return 4;
if ((d+e)%3 == 0) return 5;
if ((d-e)%3 == 0) return 6;
return 7;
}
static int
ellmult(GEN N, GEN *gl, long nbc, ulong k, GEN *X1, GEN *X2, GEN *XAUX)
{
ulong r, d, e, e1;
int res;
GEN *A = X2, *B = XAUX, *T = XAUX + 2*nbc;
ZV_aff(2*nbc,X1,XAUX);
if ((res = elldouble(N, gl, nbc, X1, X2)) != 0) return res;
r = (ulong)(k*0.61803398875 + .5);
d = k - r;
e = r - d;
while (d != e)
{
switch(get_rule(d,e))
{
case 0:
if ( (res = ecm_elladd(N, gl, nbc, A, B, T)) ) return res;
if ( (res = ecm_elladd2(N, gl, nbc, T, A, A, T, B, B)) != 0) return res;
e1 = d - e; d = (d + e1)/3; e = (e - e1)/3; break;
case 1:
if ( (res = ecm_elladd(N, gl, nbc, A, B, B)) ) return res;
if ( (res = elldouble(N, gl, nbc, A, A)) ) return res;
d = (d-e)>>1; break;
case 3:
if ( (res = elldouble(N, gl, nbc, A, A)) ) return res;
d >>= 1; break;
case 4:
if ( (res = elldouble(N, gl, nbc, A, T)) ) return res;
if ( (res = ecm_elladd(N, gl, nbc, T, A, A)) ) return res;
if ( (res = ecm_elladd(N, gl, nbc, A, B, B)) ) return res;
d = d/3 - e; break;
case 2:
if ( (res = ecm_elladd(N, gl, nbc, A, B, B)) ) return res;
d -= e; break;
case 5:
if ( (res = elldouble(N, gl, nbc, A, T)) ) return res;
if ( (res = ecm_elladd2(N, gl, nbc, T, A, A, T, B, B)) != 0) return res;
d = (d - 2*e)/3; break;
case 6:
if ( (res = ecm_elladd(N, gl, nbc, A, B, B)) ) return res;
if ( (res = elldouble(N, gl, nbc, A, T)) ) return res;
if ( (res = ecm_elladd(N, gl, nbc, T, A, A)) ) return res;
d = (d - e)/3; break;
case 7:
if ( (res = elldouble(N, gl, nbc, B, B)) ) return res;
e >>= 1; break;
}
if (d < e) { lswap(d,e); pswap(A,B); }
}
return ecm_elladd(N, gl, nbc, XAUX, X2, X2);
}
struct ECM {
pari_timer T;
long nbc, nbc2, seed;
GEN *X, *XAUX, *XT, *XD, *XB, *XB2, *XH, *Xh, *Yh;
};
static void
ECM_alloc(struct ECM *E, long lN)
{
const long bstpmax = 1024;
long spc = (13 + 48) * E->nbc2 + bstpmax * 4;
long len = spc + 385 + spc*lN;
long i, tw = evallg(lN) | evaltyp(t_INT);
GEN w, *X = (GEN*)new_chunk(len);
w = (GEN)(X + spc + 385);
for (i = spc-1; i >= 0; i--) { X[i] = w; *w = tw; w += lN; }
E->X = X;
E->XAUX = E->X + E->nbc2;
E->XT = E->XAUX + E->nbc2;
E->XD = E->XT + E->nbc2;
E->XB = E->XD + 10*E->nbc2;
E->XB2 = E->XB + 2 * bstpmax;
E->XH = E->XB2 + 2 * bstpmax;
E->Xh = E->XH + 48*E->nbc2;
E->Yh = E->XH + 192;
}
static void
ECM_init(struct ECM *E, GEN N, long nbc)
{
if (nbc < 0)
{
const long size = expi(N) + 1;
nbc = ((size >> 3) << 2) - 80;
if (nbc < 8) nbc = 8;
}
if (nbc > nbcmax) nbc = nbcmax;
E->nbc = nbc;
E->nbc2 = nbc << 1;
ECM_alloc(E, lgefint(N));
}
static GEN
ECM_loop(struct ECM *E, GEN N, ulong B1)
{
const long MR_foolproof = 16;
const long MR_fast = 1;
const ulong B2 = 110 * B1, B2_rt = usqrt(B2);
const ulong nbc = E->nbc, nbc2 = E->nbc2;
pari_sp av1, avtmp;
byteptr d0, d = diffptr;
long i, gse, gss, bstp, bstp0, rcn0, rcn;
ulong B2_p, m, p, p0;
GEN g, *XG, *YG;
GEN *X = E->X, *XAUX = E->XAUX, *XT = E->XT, *XD = E->XD;
GEN *XB = E->XB, *XB2 = E->XB2, *XH = E->XH, *Xh = E->Xh, *Yh = E->Yh;
for (i = nbc2; i--; ) affui(E->seed++, X[i]);
gse = B1 < 656
? (B1 < 200? 5: 6)
: (B1 < 10500
? (B1 < 2625? 7: 8)
: (B1 < 42000? 9: 10));
gss = 1UL << gse;
XG = XT + gse*nbc2;
YG = XG + nbc;
if (DEBUGLEVEL >= 4) {
err_printf("ECM: time = %6ld ms\nECM: B1 = %4lu,", timer_delay(&E->T), B1);
err_printf("\tB2 = %6lu,\tgss = %4ld*420\n", B2, gss);
}
p = 0;
NEXT_PRIME_VIADIFF(p,d);
B2_p = B2 >> 1;
for (m=1; m<=B2_p; m<<=1)
{
int fl = elldouble(N, &g, nbc, X, X);
if (fl > 1) return g; else if (fl) break;
}
rcn = NPRC;
while (p < B1 && p <= B2_rt)
{
pari_sp av2 = avma;
p = snextpr(p, &d, &rcn, NULL, MR_foolproof);
B2_p = B2/p;
for (m=1; m<=B2_p; m*=p)
{
int fl = ellmult(N, &g, nbc, p, X, X, XAUX);
if (fl > 1) return g; else if (fl) break;
avma = av2;
}
avma = av2;
}
while (p < B1)
{
pari_sp av2 = avma;
p = snextpr(p, &d, &rcn, NULL, MR_foolproof);
if (ellmult(N, &g, nbc, p, X, X, XAUX) > 1) return g;
avma = av2;
}
if (DEBUGLEVEL >= 4) {
err_printf("ECM: time = %6ld ms, B1 phase done, ", timer_delay(&E->T));
err_printf("p = %lu, setting up for B2\n", p);
}
if (elldouble(N, &g, nbc, X, XD) > 1) return g;
if (elldouble(N, &g, nbc, XD, XD + nbc2) > 1) return g;
if (ecm_elladd(N, &g, nbc,
XD, XD + nbc2, XD + (nbc<<2)) > 1) return g;
if (ecm_elladd2(N, &g, nbc,
XD, XD + (nbc<<2), XT + (nbc<<3),
XD + nbc2, XD + (nbc<<2), XD + (nbc<<3)) > 1)
return g;
if (DEBUGLEVEL >= 7) err_printf("\t(got [2]Q...[10]Q)\n");
p = snextpr(p, &d, &rcn, NULL, MR_foolproof);
if (rcn == NPRC)
{
rcn = prc210_no[(p % 210) >> 1];
if (rcn == NPRC)
{
err_printf("ECM: %lu should have been prime but isn\'t\n", p);
pari_err_BUG("ellfacteur");
}
}
if (ellmult(N, &g, nbc, p, X, XH + rcn*nbc2, XAUX) > 1)
return g;
if (DEBUGLEVEL >= 7)
err_printf("\t(got [p]Q, p = %lu = prc210_rp[%ld] mod 210)\n", p, rcn);
p0 = p;
d0 = d;
rcn0 = rcn;
bstp0 = 0;
for (i = 47; i; i--)
{
ulong dp = (ulong)prc210_d1[rcn];
p += dp;
if (rcn == 47)
{
if (ecm_elladd(N, &g, nbc,
XT+dp*nbc, XH+rcn*nbc2, XH) > 1) return g;
rcn = 0; continue;
}
if (ecm_elladd(N, &g, nbc,
XT+dp*nbc, XH+rcn*nbc2, XH+rcn*nbc2+nbc2) > 1)
return g;
rcn++;
}
if (DEBUGLEVEL >= 7) err_printf("\t(got initial helix)\n");
if (ellmult(N, &g, nbc, 3, XD + (nbc<<3), X, XAUX) > 1)
return g;
if (ellmult(N, &g, nbc, 7, X, X, XAUX) > 1)
return g;
if (elldouble(N, &g, nbc, X, XAUX) > 1) return g;
if (ecm_elladd(N, &g, nbc, X, XAUX, XT) > 1) return g;
if (ecm_elladd(N, &g, nbc, X, XT, XD) > 1) return g;
for (i=1; i <= gse; i++)
if (elldouble(N, &g, nbc, XT + i*nbc2, XD + i*nbc2) > 1)
return g;
if (DEBUGLEVEL >= 4)
err_printf("ECM: time = %6ld ms, entering B2 phase, p = %lu\n",
timer_delay(&E->T), p);
for (i = nbc - 4; i >= 0; i -= 4)
{
GEN *Xb;
long j, k;
if (DEBUGLEVEL >= 6)
err_printf("ECM: finishing curves %ld...%ld\n", i, i+3);
for (j = 48; j--; )
{
k = nbc2*j + i;
m = j << 2;
Xh[m] = XH[k]; Xh[m+1] = XH[k+1];
Xh[m+2] = XH[k+2]; Xh[m+3] = XH[k+3];
k += nbc;
Yh[m] = XH[k]; Yh[m+1] = XH[k+1];
Yh[m+2] = XH[k+2]; Yh[m+3] = XH[k+3];
}
for (Xb=XB,k=2,j=i; k--; Xb=XB2,j+=nbc)
{
Xb[0] = X[j]; Xb[1] = X[j+1];
Xb[2] = X[j+2]; Xb[3] = X[j+3];
Xb[4] = XAUX[j]; Xb[5] = XAUX[j+1];
Xb[6] = XAUX[j+2]; Xb[7] = XAUX[j+3];
Xb[8] = XT[j]; Xb[9] = XT[j+1];
Xb[10] = XT[j+2]; Xb[11] = XT[j+3];
Xb += 4;
for (m = 2; m < (ulong)gse+k; m++)
{
long m2 = m*nbc2 + j;
Xb += (2UL<<m);
Xb[0] = XAUX[m2]; Xb[1] = XAUX[m2+1];
Xb[2] = XAUX[m2+2]; Xb[3] = XAUX[m2+3];
}
}
if (DEBUGLEVEL >= 7)
err_printf("\t(extracted precomputed helix / baby step entries)\n");
if (ecm_elladd0(N, &g, 12, 4,
XB + 12, XB2 + 12,
XB, XB2,
XB + 16, XB2 + 16) > 1) return g;
if (ecm_elladd0(N, &g, 28, 4,
XB + 28, XB2 + 28,
XB, XB2,
XB + 32, XB2 + 32) > 1) return g;
for (m = 5; m <= (ulong)gse; m++)
{
ulong m2 = 2UL << m;
for (j = 0; (ulong)j < m2-64; j+=64)
{
if (ecm_elladd0(N, &g, 64, 4,
XB + m2-4, XB2 + m2-4,
XB + j, XB2 + j,
XB + m2+j, (m<(ulong)gse? XB2+m2+j: NULL)) > 1)
return g;
}
if (ecm_elladd0(N, &g, 60, 4,
XB + m2-4, XB2 + m2-4,
XB + j, XB2 + j,
XB + m2+j, (m<(ulong)gse? XB2+m2+j: NULL)) > 1)
return g;
}
if (DEBUGLEVEL >= 7) err_printf("\t(baby step table complete)\n");
bstp = bstp0;
p = p0; d = d0; rcn = rcn0;
g = gen_1; av1 = avma;
avtmp = (pari_sp)new_chunk(8 * lgefint(N));
while (p < B2)
{
p = snextpr(p, &d, &rcn, &bstp, MR_fast);
k = bstp - (rcn < rcn0 ? 1 : 0);
if (k > gss)
{
g = gcdii(g, N);
if (!is_pm1(g) && !equalii(g, N)) return g;
g = gen_1; avma = av1;
while (k > gss)
{
if (DEBUGLEVEL >= 7) err_printf("\t(giant step at p = %lu)\n", p);
if (ecm_elladd0(N, &g, 64, 4, XG + i, YG + i,
Xh, Yh, Xh, Yh) > 1) return g;
if (ecm_elladd0(N, &g, 64, 4, XG + i, YG + i,
Xh + 64, Yh + 64, Xh + 64, Yh + 64) > 1)
return g;
if (ecm_elladd0(N, &g, 64, 4, XG + i, YG + i,
Xh + 128, Yh + 128, Xh + 128, Yh + 128) > 1)
return g;
bstp -= (gss << 1);
k = bstp - (rcn < rcn0? 1: 0);
}
}
if (!k) continue;
if (k < 0) k = -k;
m = ((ulong)k - 1) << 2;
j = rcn<<2;
avma = avtmp;
g = modii(mulii(g, subii(XB[m], Xh[j])), N);
g = modii(mulii(g, subii(XB[m+1], Xh[j+1])), N);
g = modii(mulii(g, subii(XB[m+2], Xh[j+2])), N);
g = mulii(g, subii(XB[m+3], Xh[j+3]));
avma = av1;
g = modii(g, N);
}
avma = av1;
}
return NULL;
}
static GEN
ellfacteur(GEN N, int insist)
{
const long size = expi(N) + 1;
pari_sp av = avma;
struct ECM E;
long nbc, dsn, dsnmax, rep = 0;
if (insist)
{
const long DSNMAX = numberof(TB1)-1;
dsnmax = (size >> 2) - 10;
if (dsnmax < 0) dsnmax = 0;
else if (dsnmax > DSNMAX) dsnmax = DSNMAX;
E.seed = 1 + (nbcmax<<7)*(size&0xffff);
dsn = (size >> 3) - 5;
if (dsn < 0) dsn = 0; else if (dsn > 47) dsn = 47;
nbc = dsn + (dsn >> 2) + 9;
nbc &= ~3;
}
else
{
dsn = (size - 140) >> 3;
if (dsn < 0)
{
#ifndef __EMX__
if (DEBUGLEVEL >= 4)
err_printf("ECM: number too small to justify this stage\n");
return NULL;
#endif
dsn = 0;
} else if (dsn > 12) dsn = 12;
rep = (size <= 248 ?
(size <= 176 ? (size - 124) >> 4 : (size - 148) >> 3) :
(size - 224) >> 1);
#ifdef __EMX__
rep += 20;
#endif
dsnmax = 72;
E.seed = 1 + (nbcmax<<3)*(size & 0xf);
nbc = -1;
}
ECM_init(&E, N, nbc);
if (DEBUGLEVEL >= 4)
{
timer_start(&E.T);
err_printf("ECM: working on %ld curves at a time; initializing", E.nbc);
if (!insist)
{
if (rep == 1) err_printf(" for one round");
else err_printf(" for up to %ld rounds", rep);
}
err_printf("...\n");
}
if (dsn > dsnmax) dsn = dsnmax;
for(;;)
{
ulong B1 = insist? TB1[dsn]: TB1_for_stage[dsn];
GEN g = ECM_loop(&E, N, B1);
if (g)
{
if (DEBUGLEVEL >= 4)
err_printf("ECM: time = %6ld ms\n\tfound factor = %Ps\n",
timer_delay(&E.T), g);
return gerepilecopy(av, g);
}
if (dsn < dsnmax)
{
if (insist) dsn++;
else { dsn += 2; if (dsn > dsnmax) dsn = dsnmax; }
}
if (!insist && !--rep)
{
if (DEBUGLEVEL >= 4)
err_printf("ECM: time = %6ld ms,\tellfacteur giving up.\n",
timer_delay(&E.T));
avma = av; return NULL;
}
}
}
GEN
Z_ECM(GEN N, long rounds, long seed, ulong B1)
{
pari_sp av = avma;
struct ECM E;
long i;
E.seed = seed;
ECM_init(&E, N, -1);
if (DEBUGLEVEL >= 4) timer_start(&E.T);
for (i = rounds; i--; )
{
GEN g = ECM_loop(&E, N, B1);
if (g) return gerepilecopy(av, g);
}
avma = av; return NULL;
}
#define VALUE(x) gel(x,0)
#define EXPON(x) gel(x,1)
#define CLASS(x) gel(x,2)
INLINE void
INIT(GEN x, GEN v, GEN e, GEN c) {
VALUE(x) = v;
EXPON(x) = e;
CLASS(x) = c;
}
static void
ifac_delete(GEN x) { INIT(x,NULL,NULL,NULL); }
static void
rho_dbg(pari_timer *T, long c, long msg_mask)
{
if (c & msg_mask) return;
err_printf("Rho: time = %6ld ms,\t%3ld round%s\n",
timer_delay(T), c, (c==1?"":"s"));
}
static void
one_iter(GEN *x, GEN *P, GEN x1, GEN n, long delta)
{
*x = addis(remii(sqri(*x), n), delta);
*P = modii(mulii(*P, subii(x1, *x)), n);
}
static GEN
pollardbrent_i(GEN n, long size, long c0, long retries)
{
long tf = lgefint(n), delta, msg_mask, c, k, k1, l;
pari_sp av;
GEN x, x1, y, P, g, g1, res;
pari_timer T;
if (DEBUGLEVEL >= 4) timer_start(&T);
c = c0 << 5;
msg_mask = (size >= 448? 0x1fff:
(size >= 192? (256L<<((size-128)>>6))-1: 0xff));
y = cgeti(tf);
x1= cgeti(tf);
av = avma;
PB_RETRY:
switch ((size + retries) & 7)
{
case 0: delta= 1; break;
case 1: delta= -1; break;
case 2: delta= 3; break;
case 3: delta= 5; break;
case 4: delta= -5; break;
case 5: delta= 7; break;
case 6: delta= 11; break;
default: delta=-11; break;
}
if (DEBUGLEVEL >= 4)
{
if (!retries)
err_printf("Rho: searching small factor of %ld-bit integer\n", size);
else
err_printf("Rho: restarting for remaining rounds...\n");
err_printf("Rho: using X^2%+1ld for up to %ld rounds of 32 iterations\n",
delta, c >> 5);
}
x = gen_2; P = gen_1; g1 = NULL; k = 1; l = 1;
affui(2, y);
affui(2, x1);
for (;;)
{
one_iter(&x, &P, x1, n, delta);
if ((--c & 0x1f)==0)
{
g = gcdii(n, P); if (!is_pm1(g)) goto fin;
if (c <= 0)
{
if (DEBUGLEVEL >= 4)
err_printf("Rho: time = %6ld ms,\tPollard-Brent giving up.\n",
timer_delay(&T));
return NULL;
}
P = gen_1;
if (DEBUGLEVEL >= 4) rho_dbg(&T, c0-(c>>5), msg_mask);
affii(x,y); x = y; avma = av;
}
if (--k) continue;
if (c & 0x1f)
{
g = gcdii(n, P); if (!is_pm1(g)) goto fin;
P = gen_1;
}
if ((c -= (l>>1)) <= 0)
{
if (DEBUGLEVEL >= 4)
err_printf("Rho: time = %6ld ms,\tPollard-Brent giving up.\n",
timer_delay(&T));
return NULL;
}
c &= ~0x1f;
affii(x, x1); avma = av; x = x1;
k = l; l <<= 1;
if (DEBUGLEVEL >= 4 && (l>>7) > msg_mask)
err_printf("Rho: fast forward phase (%ld rounds of 64)...\n", l>>7);
for (k1=k; k1; k1--)
{
one_iter(&x, &P, x1, n, delta);
if ((k1 & 0x1f) == 0) gerepileall(av, 2, &x, &P);
}
if (DEBUGLEVEL >= 4 && (l>>7) > msg_mask)
err_printf("Rho: time = %6ld ms,\t%3ld rounds, back to normal mode\n",
timer_delay(&T), c0-(c>>5));
affii(x,y); P = gerepileuptoint(av, P); x = y;
}
fin:
if (!equalii(g,n))
{
if (MR_Jaeschke(g))
{
if (DEBUGLEVEL >= 4)
{
rho_dbg(&T, c0-(c>>5), 0);
err_printf("\tfound factor = %Ps\n",g);
}
return g;
}
avma = av; g1 = icopy(g);
av = avma;
}
else g1 = n;
if (DEBUGLEVEL >= 4 && size > 192)
err_printf("Rho: hang on a second, we got something here...\n");
x = y;
for(;;)
{
x = addis(remii(sqri(x), g1), delta);
g = gcdii(subii(x1, x), g1); if (!is_pm1(g)) break;
if (DEBUGLEVEL >= 4 && (--c & 0x1f) == 0) rho_dbg(&T, c0-(c>>5), msg_mask);
}
if (g1 == n || equalii(g,g1))
{
if (g1 == n && equalii(g,g1))
{
if (DEBUGLEVEL >= 4)
{
rho_dbg(&T, c0-(c>>5), 0);
err_printf("\tPollard-Brent failed.\n");
}
if (++retries >= 4) pari_err_BUG("");
goto PB_RETRY;
}
if (DEBUGLEVEL >= 4)
{
rho_dbg(&T, c0-(c>>5), 0);
err_printf("\tfound %sfactor = %Ps\n", (g1!=n ? "composite " : ""), g);
}
res = cgetg(7, t_VEC);
INIT(res+1, g, gen_1, (g1!=n? gen_0: NULL));
INIT(res+4, diviiexact(n,g), gen_1, NULL);
return res;
}
res = cgetg(10, t_VEC);
INIT(res+1, g, gen_1, NULL);
INIT(res+4, diviiexact(g1,g), gen_1, NULL);
INIT(res+7, diviiexact(n,g1), gen_1, NULL);
if (DEBUGLEVEL >= 4)
{
rho_dbg(&T, c0-(c>>5), 0);
err_printf("\tfound factors = %Ps, %Ps,\n\tand %Ps\n",
gel(res,1), gel(res,4), gel(res,7));
}
return res;
}
static GEN
pollardbrent(GEN n)
{
const long tune_pb_min = 14;
long c0, size = expi(n) + 1;
if (size <= 28)
c0 = 32;
else if (size <= 42)
c0 = tune_pb_min;
else if (size <= 59)
c0 = tune_pb_min + ((size - 42)<<1);
else if (size <= 72)
c0 = tune_pb_min + size - 24;
else if (size <= 301)
c0 = tune_pb_min + size - 60 +
((size-73)>>1)*((size-70)>>3)*((size-56)>>4);
else
c0 = 49152;
return pollardbrent_i(n, size, c0, 0);
}
GEN
Z_pollardbrent(GEN n, long rounds, long seed)
{
pari_sp av = avma;
GEN v = pollardbrent_i(n, expi(n)+1, rounds, seed);
if (!v) return NULL;
if (typ(v) == t_INT) v = mkvec2(v, diviiexact(n,v));
else if (lg(v) == 7) v = mkvec2(gel(v,1), gel(v,4));
else v = mkvec3(gel(v,1), gel(v,4), gel(v,7));
return gerepilecopy(av, v);
}
static long
squfof_ambig(long a, long B, long dd, GEN D)
{
long b, c, q, qa, qc, qcb, a0, b0, b1, c0;
long cnt = 0;
q = (dd + (B>>1)) / a;
qa = q * a;
b = (qa - B) + qa;
{
pari_sp av = avma;
c = itos(divis(shifti(subii(D, sqrs(b)), -2), a));
avma = av;
}
#ifdef DEBUG_SQUFOF
err_printf("SQUFOF: ambigous cycle of discriminant %Ps\n", D);
err_printf("SQUFOF: Form on ambigous cycle (%ld, %ld, %ld)\n", a, b, c);
#endif
a0 = a; b0 = b1 = b;
for (;;)
{
c0 = c;
if (c0 > dd)
q = 1;
else
q = (dd + (b>>1)) / c0;
if (q == 1)
{
qcb = c0 - b; b = c0 + qcb; c = a - qcb;
}
else
{
qc = q*c0; qcb = qc - b; b = qc + qcb; c = a - q*qcb;
}
a = c0;
cnt++; if (b == b1) break;
if (b == b0 && a == a0) return 0;
b1 = b;
}
q = a&1 ? a : a>>1;
if (DEBUGLEVEL >= 4)
{
if (q > 1)
err_printf("SQUFOF: found factor %ld from ambiguous form\n"
"\tafter %ld steps on the ambiguous cycle\n",
q / ugcd(q,15), cnt);
else
err_printf("SQUFOF: ...found nothing on the ambiguous cycle\n"
"\tafter %ld steps there\n", cnt);
if (DEBUGLEVEL >= 6) err_printf("SQUFOF: squfof_ambig returned %ld\n", q);
}
return q;
}
#define SQUFOF_BLACKLIST_SZ 64
static GEN
squfof(GEN n)
{
ulong d1, d2;
long tf = lgefint(n), nm4, cnt = 0;
long a1, b1, c1, dd1, L1, a2, b2, c2, dd2, L2, a, q, c, qc, qcb;
GEN D1, D2;
pari_sp av = avma;
long blacklist1[SQUFOF_BLACKLIST_SZ], blacklist2[SQUFOF_BLACKLIST_SZ];
long blp1 = 0, blp2 = 0;
int act1 = 1, act2 = 1;
#ifdef LONG_IS_64BIT
if (tf > 3 || (tf == 3 && uel(n,2) >= (1UL << (BITS_IN_LONG-5))))
#else
if (tf > 4 || (tf == 4 && (ulong)(*int_MSW(n)) >= (1UL << (BITS_IN_LONG-5))))
#endif
return NULL;
nm4 = mod4(n);
if (nm4 == 1)
{
D1 = n;
D2 = mului(5,n); d2 = itou(sqrti(D2)); dd2 = (long)((d2>>1) + (d2&1));
b2 = (long)((d2-1) | 1);
}
else
{
D1 = mului(3,n);
D2 = shifti(n,2); dd2 = itou(sqrti(n)); d2 = dd2 << 1;
b2 = (long)(d2 & (~1UL));
}
d1 = itou(sqrti(D1));
b1 = (long)((d1-1) | 1);
c1 = itos(shifti(subii(D1, sqru((ulong)b1)), -2));
if (!c1) pari_err_BUG("squfof [caller of] (n or 3n is a square)");
c2 = itos(shifti(subii(D2, sqru((ulong)b2)), -2));
if (!c2) pari_err_BUG("squfof [caller of] (5n is a square)");
L1 = (long)usqrt(d1);
L2 = (long)usqrt(d2);
dd1 = (long) ((d1>>1) + (d1&1));
a1 = a2 = 1;
if (DEBUGLEVEL >= 4)
err_printf("SQUFOF: entering main loop with forms\n"
"\t(1, %ld, %ld) and (1, %ld, %ld)\n\tof discriminants\n"
"\t%Ps and %Ps, respectively\n", b1, -c1, b2, -c2, D1, D2);
while (act1 || act2)
{
if (act1)
{
c = c1;
q = (c > dd1)? 1: (dd1 + (b1>>1)) / c;
if (q == 1)
{ qcb = c - b1; b1 = c + qcb; c1 = a1 - qcb; }
else
{ qc = q*c; qcb = qc - b1; b1 = qc + qcb; c1 = a1 - q*qcb; }
a1 = c;
if (a1 <= L1)
{
if (blp1 >= SQUFOF_BLACKLIST_SZ)
act1 = 0;
else
{
if (DEBUGLEVEL >= 6)
err_printf("SQUFOF: blacklisting a = %ld on first cycle\n", a1);
blacklist1[blp1++] = a1;
}
}
}
if (act2)
{
c = c2;
q = (c > dd2)? 1: (dd2 + (b2>>1)) / c;
if (q == 1)
{ qcb = c - b2; b2 = c + qcb; c2 = a2 - qcb; }
else
{ qc = q*c; qcb = qc - b2; b2 = qc + qcb; c2 = a2 - q*qcb; }
a2 = c;
if (a2 <= L2)
{
if (blp2 >= SQUFOF_BLACKLIST_SZ)
act2 = 0;
else
{
if (DEBUGLEVEL >= 6)
err_printf("SQUFOF: blacklisting a = %ld on second cycle\n", a2);
blacklist2[blp2++] = a2;
}
}
}
if (++cnt & 1) continue;
if (act1 && a1 == 1)
{
act1 = 0;
if (DEBUGLEVEL >= 4)
err_printf("SQUFOF: first cycle exhausted after %ld iterations,\n"
"\tdropping it\n", cnt);
}
if (act1)
{
if (uissquareall((ulong)a1, (ulong*)&a))
{
if (DEBUGLEVEL >= 4)
err_printf("SQUFOF: square form (%ld^2, %ld, %ld) on first cycle\n"
"\tafter %ld iterations\n", a, b1, -c1, cnt);
if (a <= L1)
{
long j;
for (j = 0; j < blp1; j++)
if (a == blacklist1[j]) { a = 0; break; }
}
if (a > 0)
{
q = ugcd(a, b1);
if (q > 1)
{
avma = av;
if (DEBUGLEVEL >= 4) err_printf("SQUFOF: found factor %ld^2\n", q);
return mkvec3(utoipos(q), gen_2, NULL);
}
q = squfof_ambig(a, b1, dd1, D1);
if (nm4 == 3 && q % 3 == 0) q /= 3;
if (q > 1) { avma = av; return utoipos(q); }
}
else if (DEBUGLEVEL >= 4)
err_printf("SQUFOF: ...but the root form seems to be on the "
"principal cycle\n");
}
}
if (act2 && a2 == 1)
{
act2 = 0;
if (DEBUGLEVEL >= 4)
err_printf("SQUFOF: second cycle exhausted after %ld iterations,\n"
"\tdropping it\n", cnt);
}
if (act2)
{
if (uissquareall((ulong)a2, (ulong*)&a))
{
if (DEBUGLEVEL >= 4)
err_printf("SQUFOF: square form (%ld^2, %ld, %ld) on second cycle\n"
"\tafter %ld iterations\n", a, b2, -c2, cnt);
if (a <= L2)
{
long j;
for (j = 0; j < blp2; j++)
if (a == blacklist2[j]) { a = 0; break; }
}
if (a > 0)
{
q = ugcd(a, b2);
if (q > 1)
{
avma = av;
if (DEBUGLEVEL >= 4) err_printf("SQUFOF: found factor %ld^2\n", q);
return mkvec3(utoipos(q), gen_2, NULL);
}
q = squfof_ambig(a, b2, dd2, D2);
if (nm4 == 1 && q % 5 == 0) q /= 5;
if (q > 1) { avma = av; return utoipos(q); }
}
else if (DEBUGLEVEL >= 4)
err_printf("SQUFOF: ...but the root form seems to be on the "
"principal cycle\n");
}
}
}
if (DEBUGLEVEL>=4) err_printf("SQUFOF: giving up\n");
avma = av; return NULL;
}
#if 0#endif
static ulong powersmod[106] = {
077777777ul,
077777777ul,
013562440ul,
012402540ul,
013562440ul,
052662441ul,
016603440ul,
016463450ul,
013573551ul,
012462540ul,
012462464ul,
013462771ul,
012406473ul,
012463641ul,
052463646ul,
012503446ul,
013562440ul,
052466440ul,
012472451ul,
012462454ul,
032463550ul,
013403664ul,
013463460ul,
032562565ul,
012402540ul,
052662441ul,
032672452ul,
013573551ul,
012467541ul,
012567640ul,
032706450ul,
012762452ul,
033762662ul,
012502562ul,
032463562ul,
013563440ul,
016663440ul,
036662550ul,
012462552ul,
033502450ul,
012462643ul,
033467540ul,
017403441ul,
017463462ul,
017472460ul,
033462470ul,
052566450ul,
013562640ul,
032403640ul,
016463450ul,
016463752ul,
033402440ul,
012462540ul,
012472540ul,
053562462ul,
012463465ul,
012663470ul,
052607450ul,
012566553ul,
013466440ul,
012502741ul,
012762744ul,
012763740ul,
012763443ul,
013573551ul,
013462471ul,
052502460ul,
012662463ul,
012662451ul,
012403550ul,
073567540ul,
072463445ul,
072462740ul,
012472442ul,
012462644ul,
013406650ul,
052463471ul,
012563474ul,
013503460ul,
016462441ul,
016462440ul,
012462540ul,
013462641ul,
012463454ul,
013403550ul,
057563540ul,
017466441ul,
017606471ul,
053666573ul,
012562561ul,
013473641ul,
032573440ul,
016763440ul,
016702640ul,
033762552ul,
012562550ul,
052402451ul,
033563441ul,
012663561ul,
012677560ul,
012462464ul,
032562642ul,
013402551ul,
032462450ul,
012467445ul,
032403440ul,
};
static int
check_res(ulong x, ulong N, int shift, ulong *mask)
{
long r = x%N; if ((ulong)r> (N>>1)) r = N - r;
*mask &= (powersmod[r] >> shift);
return *mask;
}
int
uis_357_powermod(ulong x, ulong *mask)
{
if ( !check_res(x, 211UL, 0, mask)) return 0;
if (*mask & 3 && !check_res(x, 209UL, 3, mask)) return 0;
if (*mask & 3 && !check_res(x, 61UL, 6, mask)) return 0;
if (*mask & 5 && !check_res(x, 203UL, 9, mask)) return 0;
if (*mask & 1 && !check_res(x, 117UL,12, mask)) return 0;
if (*mask & 3 && !check_res(x, 31UL,15, mask)) return 0;
if (*mask & 5 && !check_res(x, 43UL,18, mask)) return 0;
if (*mask & 6 && !check_res(x, 71UL,21, mask)) return 0;
return 1;
}
int
uis_357_power(ulong x, ulong *pt, ulong *mask)
{
double logx;
if (!odd(x))
{
long v = vals(x);
if (v % 7) *mask &= ~4;
if (v % 5) *mask &= ~2;
if (v % 3) *mask &= ~1;
if (!*mask) return 0;
}
if (!uis_357_powermod(x, mask)) return 0;
logx = log((double)x);
while (*mask)
{
long e, b;
ulong y, ye;
if (*mask & 1) { b = 1; e = 3; }
else if (*mask & 2) { b = 2; e = 5; }
else { b = 4; e = 7; }
y = (ulong)(exp(logx / e) + 0.5);
ye = upowuu(y,e);
if (ye == x) { *pt = y; return e; }
#ifdef LONG_IS_64BIT
if (ye > x) y--; else y++;
ye = upowuu(y,e);
if (ye == x) { *pt = y; return e; }
#endif
*mask &= ~b;
}
return 0;
}
#ifndef LONG_IS_64BIT
static int
uis_357_powermod_32bit_1(ulong x, ulong *mask)
{
if ( !check_res(x, 211UL, 0, mask)) return 0;
if (*mask & 3 && !check_res(x, 209UL, 3, mask)) return 0;
if (*mask & 3 && !check_res(x, 61UL, 6, mask)) return 0;
if (*mask & 5 && !check_res(x, 203UL, 9, mask)) return 0;
return 1;
}
static int
uis_357_powermod_32bit_2(ulong x, ulong *mask)
{
if (*mask & 1 && !check_res(x, 117UL,12, mask)) return 0;
if (*mask & 3 && !check_res(x, 31UL,15, mask)) return 0;
if (*mask & 5 && !check_res(x, 43UL,18, mask)) return 0;
if (*mask & 6 && !check_res(x, 71UL,21, mask)) return 0;
return 1;
}
#endif
int
is_357_power(GEN x, GEN *pt, ulong *mask)
{
long lx = lgefint(x);
ulong r;
pari_sp av;
GEN y;
if (!*mask) return 0;
if (DEBUGLEVEL>4) err_printf("OddPwrs: examining %ld-bit integer\n", expi(x));
if (lgefint(x) == 3) {
ulong t;
long e = uis_357_power(x[2], &t, mask);
if (e)
{
if (pt) *pt = utoi(t);
return e;
}
return 0;
}
#ifdef LONG_IS_64BIT
r = (lx == 3)? uel(x,2): umodiu(x, 6046846918939827UL);
if (!uis_357_powermod(r, mask)) return 0;
#else
r = (lx == 3)? uel(x,2): umodiu(x, 211*209*61*203);
if (!uis_357_powermod_32bit_1(r, mask)) return 0;
r = (lx == 3)? uel(x,2): umodiu(x, 117*31*43*71);
if (!uis_357_powermod_32bit_2(r, mask)) return 0;
#endif
av = avma;
while (*mask)
{
long e, b;
if (*mask & 4) { b = 4; e = 7; }
else if (*mask & 2) { b = 2; e = 5; }
else { b = 1; e = 3; }
y = mpround( sqrtnr(itor(x, nbits2prec(64 + bit_accuracy(lx) / e)), e) );
if (equalii(powiu(y,e), x))
{
if (!pt) { avma = av; return e; }
avma = (pari_sp)y; *pt = gerepileuptoint(av, y);
return e;
}
*mask &= ~b;
avma = av;
}
return 0;
}
ulong
is_kth_power(GEN x, ulong n, GEN *pt)
{
forprime_t T;
long j;
ulong q, residue;
GEN y;
pari_sp av = avma;
(void)u_forprime_arith_init(&T, odd(n)? 2*n+1: n+1, ULONG_MAX, 1,n);
if (n < 16)
j = 5;
else if (n < 32)
j = 4;
else if (n < 101)
j = 3;
else if (n < 1001)
j = 2;
else if (n < 17886697)
j = 1;
else
j = 0;
for (; j > 0; j--)
{
if (!(q = u_forprime_next(&T))) break;
residue = umodiu(x, q);
if (residue == 0)
{
if (Z_lval(x,q) % n) { avma = av; return 0; }
continue;
}
if (Fl_powu(residue, (q-1)/n, q) != 1) { avma = av; return 0; }
}
avma = av;
if (DEBUGLEVEL>4) err_printf("\nOddPwrs: [%lu] passed modular checks\n",n);
y = roundr( sqrtnr(itor(x, nbits2prec((expi(x)+16*n)/n)), n) );
if (!equalii(powiu(y, n), x)) {
if (DEBUGLEVEL>4) err_printf("\tBut it wasn't a pure power.\n");
avma = av; return 0;
}
if (!pt) avma = av; else { avma = (pari_sp)y; *pt = gerepileuptoint(av, y); }
return 1;
}
int
is_pth_power(GEN x, GEN *pt, forprime_t *T, ulong cutoffbits)
{
long cnt=0, size = expi(x) ;
ulong p;
pari_sp av = avma;
while ((p = u_forprime_next(T)) && size/p >= cutoffbits) {
long v = 1;
if (DEBUGLEVEL>5 && cnt++==2000)
{ cnt=0; err_printf("%lu%% ", 100*p*cutoffbits/size); }
while (is_kth_power(x, p, pt)) {
v *= p; x = *pt;
size = expi(x);
}
if (v > 1)
{
if (DEBUGLEVEL>5) err_printf("\nOddPwrs: is a %ld power\n",v);
return v;
}
}
if (DEBUGLEVEL>5) err_printf("\nOddPwrs: not a power\n",p);
avma = av; return 0;
}
static long ifac_insert_multiplet(GEN *, GEN *, GEN, long);
#define LAST(x) x+lg(x)-3
#define FIRST(x) x+3
#define MOEBIUS(x) gel(x,1)
#define HINT(x) gel(x,2)
INLINE void
SHALLOWCOPY(GEN x, GEN y) {
VALUE(y) = VALUE(x);
EXPON(y) = EXPON(x);
CLASS(y) = CLASS(x);
}
INLINE void
COPY(GEN x, GEN y) {
icopyifstack(VALUE(x), VALUE(y));
icopyifstack(EXPON(x), EXPON(y));
CLASS(y) = CLASS(x);
}
static void
ifac_factor_dbg(GEN x)
{
GEN c = CLASS(x), v = VALUE(x);
if (c == gen_2) err_printf("IFAC: factor %Ps\n\tis prime (finished)\n", v);
else if (c == gen_1) err_printf("IFAC: factor %Ps\n\tis prime\n", v);
else if (c == gen_0) err_printf("IFAC: factor %Ps\n\tis composite\n", v);
}
static void
ifac_check(GEN partial, GEN where)
{
if (!where || where < FIRST(partial) || where > LAST(partial))
pari_err_BUG("ifac_check ['where' out of bounds]");
}
static void
ifac_print(GEN part, GEN where)
{
long l = lg(part);
GEN p;
err_printf("ifac partial factorization structure: %ld slots, ", (l-3)/3);
if (MOEBIUS(part)) err_printf("Moebius mode, ");
err_printf("hint = %ld\n", itos(HINT(part)));
ifac_check(part, where);
for (p = part+3; p < part + l; p += 3)
{
GEN v = VALUE(p), e = EXPON(p), c = CLASS(p);
const char *s = "";
if (!v) { err_printf("[empty slot]\n"); continue; }
if (c == NULL) s = "unknown";
else if (c == gen_0) s = "composite";
else if (c == gen_1) s = "unfinished prime";
else if (c == gen_2) s = "prime";
else pari_err_BUG("unknown factor class");
err_printf("[%Ps, %Ps, %s]\n", v, e, s);
}
err_printf("Done.\n");
}
static const long decomp_default_hint = 0;
static GEN
ifac_start_hint(GEN n, int moebius, long hint)
{
const long ifac_initial_length = 3 + 7*3;
GEN here, part = cgetg(ifac_initial_length, t_VEC);
MOEBIUS(part) = moebius? gen_1 : NULL;
HINT(part) = stoi(hint);
if (isonstack(n)) n = absi(n);
here = part + ifac_initial_length - 3;
INIT(here, n,gen_1,gen_0);
while ((here -= 3) > part) ifac_delete(here);
return part;
}
GEN
ifac_start(GEN n, int moebius)
{ return ifac_start_hint(n,moebius,decomp_default_hint); }
static GEN
ifac_find(GEN partial)
{
GEN scan, end = partial + lg(partial);
#ifdef IFAC_DEBUG
ifac_check(partial, partial);
#endif
for (scan = partial+3; scan < end; scan += 3)
if (VALUE(scan)) return scan;
return NULL;
}
static void
ifac_defrag(GEN *partial, GEN *where)
{
GEN scan_new = LAST(*partial), scan_old;
for (scan_old = scan_new; scan_old >= *where; scan_old -= 3)
{
if (!VALUE(scan_old)) continue;
if (scan_old < scan_new) SHALLOWCOPY(scan_old, scan_new);
scan_new -= 3;
}
scan_new += 3;
*where = scan_new;
while ((scan_new -= 3) > *partial) ifac_delete(scan_new);
}
static void
ifac_realloc(GEN *partial, GEN *where, long new_lg)
{
long old_lg = lg(*partial);
GEN newpart, scan_new, scan_old;
if (new_lg == 1)
new_lg = 2*old_lg - 6;
else if (new_lg <= old_lg)
{
GEN first = *partial + 3;
new_lg = old_lg;
if (VALUE(first) && (CLASS(first) == gen_0 || CLASS(first)==NULL))
new_lg += 6;
}
newpart = cgetg(new_lg, t_VEC);
if (DEBUGMEM >= 3)
err_printf("IFAC: new partial factorization structure (%ld slots)\n",
(new_lg - 3)/3);
MOEBIUS(newpart) = MOEBIUS(*partial);
icopyifstack(HINT(*partial), HINT(newpart));
scan_new = newpart + new_lg - 3;
scan_old = *partial + old_lg - 3;
for (; scan_old > *partial + 2; scan_old -= 3)
{
if (*where == scan_old) *where = scan_new;
if (!VALUE(scan_old)) continue;
COPY(scan_old, scan_new); scan_new -= 3;
}
scan_new += 3;
while ((scan_new -= 3) > newpart) ifac_delete(scan_new);
*partial = newpart;
}
static void
ifac_sort_one(GEN *where, GEN washere)
{
GEN old, scan = washere - 3;
GEN value, exponent, class0, class1;
long cmp_res;
if (scan < *where) return;
value = VALUE(washere);
exponent = EXPON(washere);
class0 = CLASS(washere);
cmp_res = -1;
while (scan >= *where)
{
if (VALUE(scan))
{
cmp_res = cmpii(value, VALUE(scan));
if (cmp_res >= 0) break;
}
SHALLOWCOPY(scan, scan+3);
scan -= 3;
}
scan += 3;
if (cmp_res)
{
if (cmp_res < 0 && scan != *where)
pari_err_BUG("ifact_sort_one [misaligned partial]");
INIT(scan, value, exponent, class0); return;
}
if (DEBUGLEVEL >= 4)
err_printf("IFAC: repeated factor %Ps\n\tin ifac_sort_one\n", value);
old = scan - 3;
class1 = CLASS(old);
if (class0)
{
if (class1)
{
if (class0 == gen_0 && class1 != gen_0)
pari_err_BUG("ifac_sort_one (composite = prime)");
else if (class0 != gen_0 && class1 == gen_0)
pari_err_BUG("ifac_sort_one (prime = composite)");
else if (class0 == gen_2)
CLASS(scan) = class0;
}
else
CLASS(scan) = class0;
}
CLASS(scan) = class1;
if (EXPON(old) == gen_1 && exponent == gen_1)
EXPON(scan) = gen_2;
else
EXPON(scan) = addii(EXPON(old), exponent);
old = scan - 3;
*scan = *old;
ifac_delete(old);
if (old == *where) *where += 3;
}
static void
ifac_resort(GEN *partial, GEN *where)
{
GEN scan, end;
ifac_defrag(partial, where); end = LAST(*partial);
for (scan = *where; scan <= end; scan += 3)
if (VALUE(scan) && !CLASS(scan)) ifac_sort_one(where, scan);
ifac_defrag(partial, where);
}
int
ifac_isprime(GEN x)
{
if (!BPSW_psp_nosmalldiv(x)) return 0;
if (factor_proven && ! BPSW_isprime(x))
{
pari_warn(warner,
"IFAC: pseudo-prime %Ps\n\tis not prime. PLEASE REPORT!\n", x);
return 0;
}
return 1;
}
static int
ifac_checkprime(GEN x)
{
int res = ifac_isprime(VALUE(x));
CLASS(x) = res? gen_1: gen_0;
if (DEBUGLEVEL>2) ifac_factor_dbg(x);
return res;
}
static void
ifac_whoiswho(GEN *partial, GEN *where, long after_crack)
{
GEN scan, scan_end = LAST(*partial);
#ifdef IFAC_DEBUG
ifac_check(*partial, *where);
#endif
if (after_crack == 0) return;
if (after_crack > 0)
scan = *where + 3*(after_crack - 1);
else
for (scan = scan_end; scan >= *where; scan -= 3)
{
if (CLASS(scan))
{
if (CLASS(scan) == gen_0) break;
if (CLASS(scan) == gen_1)
{
if (DEBUGLEVEL>=3)
{
err_printf("IFAC: factor %Ps\n\tis prime (no larger composite)\n",
VALUE(*where));
err_printf("IFAC: prime %Ps\n\tappears with exponent = %ld\n",
VALUE(*where), itos(EXPON(*where)));
}
CLASS(scan) = gen_2;
}
continue;
}
if (!ifac_checkprime(scan)) break;
CLASS(scan) = gen_2;
if (DEBUGLEVEL>2) ifac_factor_dbg(scan);
}
for (; scan >= *where; scan -= 3)
{
if (CLASS(scan)) continue;
(void)ifac_checkprime(scan);
}
}
static long
ifac_divide(GEN *partial, GEN *where, long moebius_mode)
{
GEN scan, scan_end = LAST(*partial);
long res = 0, exponent, newexp, otherexp;
#ifdef IFAC_DEBUG
ifac_check(*partial, *where);
if (CLASS(*where) != gen_1)
pari_err_BUG("ifac_divide [division by composite or finished prime]");
if (!VALUE(*where)) pari_err_BUG("ifac_divide [division by nothing]");
#endif
newexp = exponent = itos(EXPON(*where));
if (exponent > 1 && moebius_mode) return 1;
for (scan = *where+3; scan <= scan_end; scan += 3)
{
if (CLASS(scan) != gen_0) continue;
otherexp = 0;
while (dvdiiz(VALUE(scan), VALUE(*where), VALUE(scan)))
{
if (moebius_mode) return 1;
if (!otherexp) otherexp = itos(EXPON(scan));
newexp += otherexp;
}
if (newexp > exponent)
{
EXPON(*where) = (newexp == 2 ? gen_2 : utoipos(newexp));
exponent = newexp;
if (is_pm1((GEN)*scan))
{
ifac_delete(scan);
if (DEBUGLEVEL >= 4)
err_printf("IFAC: a factor was a power of another prime factor\n");
} else {
CLASS(scan) = NULL;
if (DEBUGLEVEL >= 4)
err_printf("IFAC: a factor was divisible by another prime factor,\n"
"\tleaving a cofactor = %Ps\n", VALUE(scan));
}
res = 1;
if (DEBUGLEVEL >= 5)
err_printf("IFAC: prime %Ps\n\tappears at least to the power %ld\n",
VALUE(*where), newexp);
}
}
CLASS(*where) = gen_2;
if (DEBUGLEVEL >= 3)
err_printf("IFAC: prime %Ps\n\tappears with exponent = %ld\n",
VALUE(*where), newexp);
return res;
}
static void
update_pow(GEN where, GEN factor, long exp, pari_sp *av)
{
GEN ex = EXPON(where);
if (DEBUGLEVEL>3)
err_printf("IFAC: found %Ps =\n\t%Ps ^%ld\n", *where, factor, exp);
affii(factor, VALUE(where)); avma = *av;
if (ex == gen_1)
{ EXPON(where) = exp == 2? gen_2: utoipos(exp); *av = avma; }
else if (ex == gen_2)
{ EXPON(where) = utoipos(exp<<1); *av = avma; }
else
affsi(exp * itos(ex), EXPON(where));
}
#define get_hint(partial) (itos(HINT(*partial)) & 15)
static long
ifac_crack(GEN *partial, GEN *where, long moebius_mode)
{
long cmp_res, hint = get_hint(partial);
GEN factor, exponent;
#ifdef IFAC_DEBUG
ifac_check(*partial, *where);
if (*where < *partial + 6)
pari_err_BUG("ifac_crack ['*where' out of bounds]");
if (!(VALUE(*where)) || typ(VALUE(*where)) != t_INT)
pari_err_BUG("ifac_crack [incorrect VALUE(*where)]");
if (CLASS(*where) != gen_0)
pari_err_BUG("ifac_crack [operand not known composite]");
#endif
if (DEBUGLEVEL>2) {
err_printf("IFAC: cracking composite\n\t%Ps\n", **where);
if (DEBUGLEVEL>3) err_printf("IFAC: checking for pure square\n");
}
{
forprime_t T;
ulong exp = 1, mask = 7;
long good = 0;
pari_sp av = avma;
(void)u_forprime_init(&T, 11, ULONG_MAX);
while (Z_issquareall(VALUE(*where), &factor))
{
good = 1;
update_pow(*where, factor, 2, &av);
if (moebius_mode) return 0;
}
while ( (exp = is_357_power(VALUE(*where), &factor, &mask)) )
{
good = 1;
update_pow(*where, factor, exp, &av);
if (moebius_mode) return 0;
}
while ( (exp = is_pth_power(VALUE(*where), &factor, &T, 15)) )
{
good = 1;
update_pow(*where, factor, exp, &av);
if (moebius_mode) return 0;
}
if (good && hint != 15 && ifac_checkprime(*where))
{
if (DEBUGLEVEL>3)
err_printf("IFAC: factor %Ps\n\tis prime\n", VALUE(*where));
return 0;
}
}
factor = NULL;
if (!(hint & 4))
{
if (DEBUGLEVEL >= 4) err_printf("IFAC: trying Pollard-Brent rho method\n");
factor = pollardbrent(VALUE(*where));
if (!factor)
{
if (DEBUGLEVEL >= 4)
err_printf("IFAC: trying Shanks' SQUFOF, will fail silently if input\n"
" is too large for it.\n");
factor = squfof(VALUE(*where));
}
}
if (!factor && !(hint & 2))
{
if (DEBUGLEVEL >= 4) err_printf("IFAC: trying Lenstra-Montgomery ECM\n");
factor = ellfacteur(VALUE(*where), 0);
}
if (!factor && !(hint & 1))
{
if (DEBUGLEVEL >= 4) err_printf("IFAC: trying MPQS\n");
factor = mpqs(VALUE(*where));
}
if (!factor)
{
if (!(hint & 8))
{
if (DEBUGLEVEL >= 4)
err_printf("IFAC: forcing ECM, may take some time\n");
factor = ellfacteur(VALUE(*where), 1);
}
else
{
if (DEBUGLEVEL >= 2)
{
if (hint != 15)
pari_warn(warner, "IFAC: unfactored composite declared prime");
else
pari_warn(warner, "IFAC: untested integer declared prime");
if (DEBUGLEVEL == 2) err_printf("\t%Ps\n", VALUE(*where));
}
CLASS(*where) = gen_1;
return 1;
}
}
if (typ(factor) == t_VEC)
return ifac_insert_multiplet(partial, where, factor, moebius_mode);
if (!dvdiiz(VALUE(*where), factor, VALUE(*where)))
{
err_printf("IFAC: factoring %Ps\n", VALUE(*where));
err_printf("\tyielded 'factor' %Ps\n\twhich isn't!\n", factor);
pari_err_BUG("factoring");
}
if (DEBUGLEVEL >= 4) err_printf("IFAC: cofactor = %Ps\n", VALUE(*where));
cmp_res = cmpii(factor, VALUE(*where));
CLASS(*where) = NULL;
exponent = EXPON(*where);
*where -= 3;
CLASS(*where) = NULL;
EXPON(*where) = isonstack(exponent)? icopy(exponent): exponent;
if (cmp_res < 0)
VALUE(*where) = factor;
else if (cmp_res > 0)
{
GEN old = *where + 3;
VALUE(*where) = VALUE(old);
VALUE(old) = factor;
}
else pari_err_BUG("ifac_crack [Z_issquareall miss]");
return 2;
}
static long
ifac_insert_multiplet(GEN *partial, GEN *where, GEN facvec, long moebius_mode)
{
long j,k=1, lfv=lg(facvec)-1, nf=lfv/3, room=(long)(*where-*partial);
long needroom = lfv - room;
GEN e, newexp, cur, sorted, auxvec = cgetg(nf+1, t_VEC), factor;
long exponent = itos(EXPON(*where));
if (DEBUGLEVEL >= 5)
err_printf("IFAC: incorporating set of %ld factor(s)\n", nf);
if (needroom > 0)
ifac_realloc(partial, where, lg(*partial) + needroom + 3);
for (j=nf; j; j--) auxvec[j] = facvec[3*j-2];
sorted = indexsort(auxvec);
for (j=nf; j; j--) sorted[j] = 3*sorted[j]-2;
cur = facvec + sorted[nf];
VALUE(*where) = VALUE(cur);
newexp = EXPON(cur);
if (newexp != gen_1)
{
if (exponent == 1)
e = isonstack(newexp)? icopy(newexp): newexp;
else
e = mului(exponent, newexp);
EXPON(*where) = e;
}
CLASS(*where) = CLASS(cur);
if (DEBUGLEVEL >= 6) err_printf("\tstored (largest) factor no. %ld...\n", nf);
for (j=nf-1; j; j--)
{
cur = facvec + sorted[j];
factor = VALUE(cur);
if (equalii(factor, VALUE(*where)))
{
if (DEBUGLEVEL >= 6)
err_printf("\tfactor no. %ld is a duplicate%s\n", j, (j>1? "...": ""));
newexp = EXPON(cur);
if (newexp != gen_1)
e = addis(EXPON(*where), exponent * itos(newexp));
else if (EXPON(*where) == gen_1 && exponent == 1)
e = gen_2;
else
e = addis(EXPON(*where), exponent);
EXPON(*where) = e;
if (moebius_mode) return 0;
continue;
}
*where -= 3;
CLASS(*where) = CLASS(cur);
newexp = EXPON(cur);
if (newexp != gen_1)
{
if (exponent == 1 && newexp == gen_2)
e = gen_2;
else
e = mului(exponent, newexp);
}
else
e = (exponent == 1 ? gen_1 :
(exponent == 2 ? gen_2 :
utoipos(exponent)));
EXPON(*where) = e;
VALUE(*where) = isonstack(factor) ? icopy(factor) : factor;
k++;
if (DEBUGLEVEL >= 6)
err_printf("\tfactor no. %ld was unique%s\n", j, j>1? " (so far)...": "");
}
*sorted = evaltyp(t_INT) | evallg(nf+1);
return k;
}
static GEN
ifac_main(GEN *partial)
{
const long moebius_mode = !!MOEBIUS(*partial);
GEN here = ifac_find(*partial);
long nf;
if (!here) return NULL;
while (CLASS(here) != gen_2)
{
if (CLASS(here) == gen_0)
{
if (here < *partial + 6)
{
ifac_defrag(partial, &here);
if (here < *partial + 6) ifac_realloc(partial, &here, 1);
}
nf = ifac_crack(partial, &here, moebius_mode);
if (moebius_mode && EXPON(here) != gen_1)
{
if (DEBUGLEVEL >= 3)
err_printf("IFAC: main loop: repeated new factor\n\t%Ps\n", *here);
return gen_0;
}
ifac_whoiswho(partial, &here, nf);
continue;
}
if (CLASS(here) == gen_1)
{
if (ifac_divide(partial, &here, moebius_mode))
{
if (moebius_mode)
{
if (DEBUGLEVEL >= 3)
err_printf("IFAC: main loop: another factor was divisible by\n"
"\t%Ps\n", *here);
return gen_0;
}
ifac_resort(partial, &here);
ifac_whoiswho(partial, &here, -1);
}
continue;
}
pari_err_BUG("ifac_main [non-existent factor class]");
}
if (moebius_mode && EXPON(here) != gen_1)
{
if (DEBUGLEVEL >= 3)
err_printf("IFAC: after main loop: repeated old factor\n\t%Ps\n", *here);
return gen_0;
}
if (DEBUGLEVEL >= 4)
{
nf = (*partial + lg(*partial) - here - 3)/3;
if (nf)
err_printf("IFAC: main loop: %ld factor%s left\n", nf, (nf>1)? "s": "");
else
err_printf("IFAC: main loop: this was the last factor\n");
}
if (factor_add_primes && !(get_hint(partial) & 8))
{
GEN p = VALUE(here);
if (lgefint(p)>3 || uel(p,2) > 0x1000000UL) (void)addprimes(p);
}
return here;
}
static long
ifac_decomp(GEN n, long hint)
{
pari_sp av = avma;
long nb = 0;
GEN part, here, workspc, pairs = (GEN)av;
workspc = new_chunk((expi(n) + 1) * 7);
part = ifac_start_hint(n, 0, hint);
for (;;)
{
here = ifac_main(&part);
if (!here) break;
if (gc_needed(av,1))
{
long offset;
if(DEBUGMEM>1)
{
pari_warn(warnmem,"[2] ifac_decomp");
ifac_print(part, here);
}
ifac_realloc(&part, &here, 0);
offset = here - part;
part = gerepileupto((pari_sp)workspc, part);
here = part + offset;
}
nb++;
pairs = icopy_avma(VALUE(here), (pari_sp)pairs);
pairs = icopy_avma(EXPON(here), (pari_sp)pairs);
ifac_delete(here);
}
avma = (pari_sp)pairs;
if (DEBUGLEVEL >= 3)
err_printf("IFAC: found %ld large prime (power) factor%s.\n",
nb, (nb>1? "s": ""));
return nb;
}
static void
ifac_GC(pari_sp av, GEN *part)
{
GEN here = NULL;
if(DEBUGMEM>1) pari_warn(warnmem,"ifac_xxx");
ifac_realloc(part, &here, 0);
*part = gerepileupto(av, *part);
}
static long
ifac_moebius(GEN n)
{
long mu = 1;
pari_sp av = avma;
GEN part = ifac_start(n, 1);
for(;;)
{
long v;
GEN p;
if (!ifac_next(&part,&p,&v)) return v? 0: mu;
mu = -mu;
if (gc_needed(av,1)) ifac_GC(av,&part);
}
}
int
ifac_read(GEN part, GEN *p, long *e)
{
GEN here = ifac_find(part);
if (!here) return 0;
*p = VALUE(here);
*e = EXPON(here)[2];
return 1;
}
void
ifac_skip(GEN part)
{
GEN here = ifac_find(part);
if (here) ifac_delete(here);
}
static int
ifac_ispowerful(GEN n)
{
pari_sp av = avma;
GEN part = ifac_start(n, 0);
for(;;)
{
long e;
GEN p;
if (!ifac_read(part,&p,&e)) return 1;
if (e != 1 || Z_isanypower(p,NULL)) { ifac_skip(part); continue; }
if (!ifac_next(&part,&p,&e)) return 1;
if (e == 1) return 0;
if (gc_needed(av,1)) ifac_GC(av,&part);
}
}
static GEN
ifac_core(GEN n)
{
GEN m = gen_1, c = cgeti(lgefint(n));
pari_sp av = avma;
GEN part = ifac_start(n, 0);
for(;;)
{
long e;
GEN p;
if (!ifac_read(part,&p,&e)) return m;
if (!odd(e) || Z_issquare(p)) { ifac_skip(part); continue; }
if (!ifac_next(&part,&p,&e)) return m;
if (odd(e)) m = mulii(m, p);
if (gc_needed(av,1)) { affii(m,c); m=c; ifac_GC(av,&part); }
}
}
ulong
tridiv_bound(GEN n)
{
ulong l = (ulong)expi(n) + 1;
if (l <= 32) return 1UL<<14;
if (l <= 512) return (l-16) << 10;
return 1UL<<19;
}
static ulong
utridiv_bound(ulong n)
{
#ifdef LONG_IS_64BIT
if (n & HIGHMASK)
return ((ulong)expu(n) + 1 - 16) << 10;
#else
(void)n;
#endif
return 1UL<<14;
}
static void
ifac_factoru(GEN n, long hint, GEN P, GEN E, long *pi)
{
GEN part = ifac_start_hint(n, 0, hint);
for(;;)
{
long v;
GEN p;
if (!ifac_next(&part,&p,&v)) return;
P[*pi] = itou(p);
E[*pi] = v;
(*pi)++;
}
}
static long
ifac_moebiusu(GEN n)
{
GEN part = ifac_start(n, 1);
long s = 1;
for(;;)
{
long v;
GEN p;
if (!ifac_next(&part,&p,&v)) return v? 0: s;
s = -s;
}
}
INLINE ulong
u_forprime_next_fast(forprime_t *T)
{
if (*(T->d))
{
NEXT_PRIME_VIADIFF(T->p, T->d);
return T->p > T->b ? 0: T->p;
}
return u_forprime_next(T);
}
static GEN
factoru_sign(ulong n, ulong all, long hint)
{
GEN f, E, E2, P, P2;
pari_sp av;
ulong p, lim;
long i;
forprime_t S;
if (n == 0) retmkvec2(mkvecsmall(0), mkvecsmall(1));
if (n == 1) retmkvec2(cgetg(1,t_VECSMALL), cgetg(1,t_VECSMALL));
f = cgetg(3,t_VEC); av = avma;
lim = all; if (!lim) lim = utridiv_bound(n);
(void)new_chunk(16*2);
P = cgetg(16, t_VECSMALL); i = 1;
E = cgetg(16, t_VECSMALL);
if (lim > 2)
{
long v = vals(n), oldi;
if (v)
{
P[1] = 2; E[1] = v; i = 2;
n >>= v; if (n == 1) goto END;
}
u_forprime_init(&S, 3, lim-1);
oldi = i;
while ( (p = u_forprime_next_fast(&S)) )
{
int stop;
if (p == 673)
{
oldi = i;
if (uisprime_661(n)) { P[i] = n; E[i] = 1; i++; goto END; }
}
v = u_lvalrem_stop(&n, p, &stop);
if (v) {
P[i] = p;
E[i] = v; i++;
}
if (stop) {
if (n != 1) { P[i] = n; E[i] = 1; i++; }
goto END;
}
}
if (oldi != i && uisprime_661(n)) { P[i] = n; E[i] = 1; i++; goto END; }
}
if (all)
{
#ifdef LONG_IS_64BIT
ulong mask = all > 563 ? (all > 7129 ? 1: 3): 7;
#else
ulong mask = all > 22 ? (all > 83 ? 1: 3): 7;
#endif
long k = 1, ex;
while (uissquareall(n, &n)) k <<= 1;
while ( (ex = uis_357_power(n, &n, &mask)) ) k *= ex;
P[i] = n; E[i] = k; i++; goto END;
}
{
GEN perm;
ifac_factoru(utoipos(n), hint, P, E, &i);
setlg(P, i);
perm = vecsmall_indexsort(P);
P = vecsmallpermute(P, perm);
E = vecsmallpermute(E, perm);
}
END:
avma = av;
P2 = cgetg(i, t_VECSMALL); gel(f,1) = P2;
E2 = cgetg(i, t_VECSMALL); gel(f,2) = E2;
while (--i >= 1) { P2[i] = P[i]; E2[i] = E[i]; }
return f;
}
GEN
factoru(ulong n)
{ return factoru_sign(n, 0, decomp_default_hint); }
long
moebiusu_fact(GEN f)
{
GEN E = gel(f,2);
long i, l = lg(E);
for (i = 1; i < l; i++)
if (E[i] > 1) return 0;
return odd(l)? 1: -1;
}
long
moebiusu(ulong n)
{
pari_sp av;
ulong p;
long s, v, test_prime;
forprime_t S;
switch(n)
{
case 0: (void)check_arith_non0(gen_0,"moebius");
case 1: return 1;
case 2: return -1;
}
v = vals(n);
if (v == 0)
s = 1;
else
{
if (v > 1) return 0;
n >>= 1;
s = -1;
}
av = avma;
u_forprime_init(&S, 3, utridiv_bound(n));
test_prime = 0;
while ((p = u_forprime_next_fast(&S)))
{
int stop;
if (p == 673)
{
test_prime = 0;
if (uisprime_661(n)) { avma = av; return -s; }
}
v = u_lvalrem_stop(&n, p, &stop);
if (v) {
if (v > 1) { avma = av; return 0; }
test_prime = 1;
s = -s;
}
if (stop) { avma = av; return n == 1? s: -s; }
}
avma = av;
if (test_prime && uisprime_661(n)) return -s;
else
{
long t = ifac_moebiusu(utoipos(n));
avma = av;
if (t == 0) return 0;
return (s == t)? 1: -1;
}
}
long
moebius(GEN n)
{
pari_sp av = avma;
GEN F;
ulong p;
long i, l, s, v;
forprime_t S;
if ((F = check_arith_non0(n,"moebius")))
{
GEN E;
F = clean_Z_factor(F);
E = gel(F,2);
l = lg(E);
for(i = 1; i < l; i++)
if (!equali1(gel(E,i))) { avma = av; return 0; }
avma = av; return odd(l)? 1: -1;
}
if (lgefint(n) == 3) return moebiusu(uel(n,2));
p = mod4(n); if (!p) return 0;
if (p == 2) { s = -1; n = shifti(n, -1); } else { s = 1; n = icopy(n); }
setabssign(n);
u_forprime_init(&S, 3, tridiv_bound(n));
while ((p = u_forprime_next_fast(&S)))
{
int stop;
v = Z_lvalrem_stop(&n, p, &stop);
if (v)
{
if (v > 1) { avma = av; return 0; }
s = -s;
if (stop) { avma = av; return is_pm1(n)? s: -s; }
}
}
l = lg(primetab);
for (i = 1; i < l; i++)
{
v = Z_pvalrem(n, gel(primetab,i), &n);
if (v)
{
if (v > 1) { avma = av; return 0; }
s = -s;
if (is_pm1(n)) { avma = av; return s; }
}
}
if (ifac_isprime(n)) { avma = av; return -s; }
v = ifac_moebius(n);
avma = av; return (s<0 ? -v : v);
}
long
ispowerful(GEN n)
{
pari_sp av = avma;
GEN F;
ulong p, bound;
long i, l, v;
forprime_t S;
if ((F = check_arith_all(n, "ispowerful")))
{
GEN p, P = gel(F,1), E = gel(F,2);
if (lg(P) == 1) return 1;
p = gel(P,1);
if (!signe(p)) return 1;
i = is_pm1(p)? 2: 1;
l = lg(E);
for (; i < l; i++)
if (equali1(gel(E,i))) return 0;
return 1;
}
if (!signe(n)) return 1;
if (mod4(n) == 2) return 0;
n = shifti(n, -vali(n));
if (is_pm1(n)) return 1;
setabssign(n);
bound = tridiv_bound(n);
u_forprime_init(&S, 3, bound);
while ((p = u_forprime_next_fast(&S)))
{
int stop;
v = Z_lvalrem_stop(&n, p, &stop);
if (v)
{
if (v == 1) { avma = av; return 0; }
if (stop) { avma = av; return is_pm1(n); }
}
}
l = lg(primetab);
for (i = 1; i < l; i++)
{
v = Z_pvalrem(n, gel(primetab,i), &n);
if (v)
{
if (v == 1) { avma = av; return 0; }
if (is_pm1(n)) { avma = av; return 1; }
}
}
if(cmpii(powuu(bound+1, 3), n) > 0) {
long res = Z_issquare(n);
avma = av; return res;
}
if (ifac_isprime(n)) { avma=av; return 0; }
v = ifac_ispowerful(n);
avma = av; return v;
}
ulong
coreu_fact(GEN f)
{
GEN P = gel(f,1), E = gel(f,2);
long i, l = lg(P), m = 1;
for (i = 1; i < l; i++)
{
ulong p = P[i], e = E[i];
if (e & 1) m *= p;
}
return m;
}
ulong
coreu(ulong n)
{
if (n == 0) return 0;
else
{
pari_sp av = avma;
long m = coreu_fact(factoru(n));
avma = av; return m;
}
}
GEN
core(GEN n)
{
pari_sp av = avma;
GEN m, F;
ulong p;
long i, l, v;
forprime_t S;
if ((F = check_arith_all(n, "core")))
{
GEN p, x, P = gel(F,1), E = gel(F,2);
long j = 1;
if (lg(P) == 1) return gen_1;
p = gel(P,1);
if (!signe(p)) return gen_0;
l = lg(P); x = cgetg(l, t_VEC);
for (i = 1; i < l; i++)
if (mpodd(gel(E,i))) gel(x,j++) = gel(P,i);
setlg(x, j); return ZV_prod(x);
}
switch(lgefint(n))
{
case 2: return gen_0;
case 3:
p = coreu(uel(n,2));
return signe(n) > 0? utoipos(p): utoineg(p);
}
m = signe(n) < 0? gen_m1: gen_1;
n = absi_shallow(n);
u_forprime_init(&S, 2, tridiv_bound(n));
while ((p = u_forprime_next_fast(&S)))
{
int stop;
v = Z_lvalrem_stop(&n, p, &stop);
if (v)
{
if (v & 1) m = muliu(m, p);
if (stop)
{
if (!is_pm1(n)) m = mulii(m, n);
return gerepileuptoint(av, m);
}
}
}
l = lg(primetab);
for (i = 1; i < l; i++)
{
GEN q = gel(primetab,i);
v = Z_pvalrem(n, q, &n);
if (v)
{
if (v & 1) m = mulii(m, q);
if (is_pm1(n)) return gerepileuptoint(av, m);
}
}
if (ifac_isprime(n)) { m = mulii(m, n); return gerepileuptoint(av, m); }
if (m == gen_1) n = icopy(n);
return gerepileuptoint(av, mulii(m, ifac_core(n)));
}
long
Z_issmooth(GEN m, ulong lim)
{
pari_sp av=avma;
ulong p = 2;
forprime_t S;
u_forprime_init(&S, 2, lim);
while ((p = u_forprime_next_fast(&S)))
{
int stop;
(void)Z_lvalrem_stop(&m, p, &stop);
if (stop) { avma = av; return abscmpiu(m,lim)<=0; }
}
avma = av; return 0;
}
GEN
Z_issmooth_fact(GEN m, ulong lim)
{
pari_sp av=avma;
GEN F, P, E;
ulong p;
long i = 1, l = expi(m)+1;
forprime_t S;
P = cgetg(l, t_VECSMALL);
E = cgetg(l, t_VECSMALL);
F = mkmat2(P,E);
u_forprime_init(&S, 2, lim);
while ((p = u_forprime_next_fast(&S)))
{
long v;
int stop;
if ((v = Z_lvalrem_stop(&m, p, &stop)))
{
P[i] = p;
E[i] = v; i++;
if (stop)
{
if (abscmpiu(m,lim) > 0) break;
P[i] = m[2];
E[i] = 1; i++;
setlg(P, i);
setlg(E, i); avma = (pari_sp)F; return F;
}
}
}
avma = av; return NULL;
}
static GEN
aux_end(GEN M, GEN n, long nb)
{
GEN P,E, z = (GEN)avma;
long i;
if (n) gunclone(n);
P = cgetg(nb+1,t_COL);
E = cgetg(nb+1,t_COL);
for (i=nb; i; i--)
{
while (typ(z) != t_INT) z += lg(z);
gel(E,i) = z; z += lg(z);
gel(P,i) = z; z += lg(z);
}
gel(M,1) = P;
gel(M,2) = E;
return sort_factor(M, (void*)&abscmpii, cmp_nodata);
}
static void
STORE(long *nb, GEN x, long e) { (*nb)++; (void)x; (void)utoipos(e); }
static void
STOREu(long *nb, ulong x, long e) { STORE(nb, utoipos(x), e); }
static void
STOREi(long *nb, GEN x, long e) { STORE(nb, icopy(x), e); }
static int
special_primes(GEN n, ulong p, long *nb, GEN T)
{
long i, l = lg(T);
if (l > 1)
{
long pp[] = { evaltyp(t_INT)|_evallg(4), 0,0,0 };
pari_sp av = avma; affii(sqru(p), pp); avma = av;
for (i = 1; i < l; i++)
if (dvdiiz(n,gel(T,i), n))
{
long k = 1; while (dvdiiz(n,gel(T,i), n)) k++;
STOREi(nb, gel(T,i), k);
if (abscmpii(pp, n) > 0) return 1;
}
}
return 0;
}
static GEN
ifactor_sign(GEN n, ulong all, long hint, long sn)
{
GEN M, N;
pari_sp av;
long nb = 0, i;
ulong lim;
forprime_t T;
if (!sn) retmkmat2(mkcol(gen_0), mkcol(gen_1));
if (lgefint(n) == 3)
{
GEN f, Pf, Ef, P, E, F = cgetg(3, t_MAT);
long l;
av = avma;
(void)new_chunk((15*3 + 15 + 1) * 2);
f = factoru_sign(uel(n,2), all, hint);
avma = av;
Pf = gel(f,1);
Ef = gel(f,2);
l = lg(Pf);
if (sn < 0)
{
long L = l+1;
gel(F,1) = P = cgetg(L, t_COL);
gel(F,2) = E = cgetg(L, t_COL);
gel(P,1) = gen_m1; P++;
gel(E,1) = gen_1; E++;
}
else
{
gel(F,1) = P = cgetg(l, t_COL);
gel(F,2) = E = cgetg(l, t_COL);
}
for (i = 1; i < l; i++)
{
gel(P,i) = utoipos(Pf[i]);
gel(E,i) = utoipos(Ef[i]);
}
return F;
}
M = cgetg(3,t_MAT);
if (sn < 0) STORE(&nb, utoineg(1), 1);
if (is_pm1(n)) return aux_end(M,NULL,nb);
n = N = gclone(n); setabssign(n);
lim = all; if (!lim) lim = tridiv_bound(n);
if (lim > 2)
{
ulong maxp, p;
pari_sp av2;
i = vali(n);
if (i)
{
STOREu(&nb, 2, i);
av = avma; affii(shifti(n,-i), n); avma = av;
}
if (is_pm1(n)) return aux_end(M,n,nb);
maxp = maxprime();
av = avma; u_forprime_init(&T, 3, minss(lim, maxp)); av2 = avma;
while ((p = u_forprime_next_fast(&T)))
{
pari_sp av3 = avma;
int stop;
long k = Z_lvalrem_stop(&n, p, &stop);
if (k)
{
affii(n, N); n = N; avma = av3;
STOREu(&nb, p, k);
}
if (stop)
{
if (!is_pm1(n)) STOREi(&nb, n, 1);
stackdummy(av, av2);
return aux_end(M,n,nb);
}
}
stackdummy(av, av2);
if (lim > maxp)
{
av = avma; u_forprime_init(&T, maxp+1, lim); av2 = avma;
while ((p = u_forprime_next(&T)))
{
pari_sp av3 = avma;
int stop;
long k = Z_lvalrem_stop(&n, p, &stop);
if (k)
{
affii(n, N); n = N; avma = av3;
STOREu(&nb, p, k);
}
if (stop)
{
if (!is_pm1(n)) STOREi(&nb, n, 1);
stackdummy(av, av2);
return aux_end(M,n,nb);
}
}
stackdummy(av, av2);
}
}
if (special_primes(n, lim, &nb, primetab))
{
if (!is_pm1(n)) STOREi(&nb, n, 1);
return aux_end(M,n,nb);
}
if (all)
{
GEN x;
long k;
av = avma;
k = isanypower_nosmalldiv(n, &x);
if (k > 1) affii(x, n);
avma = av; STOREi(&nb, n, k);
if (DEBUGLEVEL >= 2) {
pari_warn(warner,
"IFAC: untested %ld-bit integer declared prime", expi(n));
if (expi(n) <= 256)
err_printf("\t%Ps\n", n);
}
return aux_end(M,n,nb);
}
if (ifac_isprime(n)) { STOREi(&nb, n, 1); return aux_end(M,n,nb); }
nb += ifac_decomp(n, hint);
return aux_end(M,n, nb);
}
static GEN
ifactor(GEN n, ulong all, long hint)
{ return ifactor_sign(n, all, hint, signe(n)); }
int
ifac_next(GEN *part, GEN *p, long *e)
{
GEN here = ifac_main(part);
if (here == gen_0) { *p = NULL; *e = 1; return 0; }
if (!here) { *p = NULL; *e = 0; return 0; }
*p = VALUE(here);
*e = EXPON(here)[2];
ifac_delete(here); return 1;
}
GEN
factorint(GEN n, long flag)
{
GEN F;
if ((F = check_arith_all(n,"factorint"))) return gcopy(F);
return ifactor(n,0,flag);
}
GEN
Z_factor_limit(GEN n, ulong all)
{
if (!all) all = GP_DATA->primelimit + 1;
return ifactor(n,all,decomp_default_hint);
}
GEN
absZ_factor_limit(GEN n, ulong all)
{
if (!all) all = GP_DATA->primelimit + 1;
return ifactor_sign(n,all,decomp_default_hint, signe(n)?1 : 0);
}
GEN
Z_factor(GEN n)
{ return ifactor(n,0,decomp_default_hint); }
GEN
absZ_factor(GEN n)
{ return ifactor_sign(n, 0, decomp_default_hint, signe(n)? 1: 0); }
GEN
Z_factor_until(GEN n, GEN limit)
{
pari_sp av2, av = avma;
ulong B = tridiv_bound(n);
GEN q, part, F = ifactor(n, B, decomp_default_hint);
GEN P = gel(F,1), E = gel(F,2);
long l = lg(P);
av2 = avma;
q = gel(P,l-1);
if (abscmpiu(q, B) <= 0 || cmpii(q, sqru(B)) < 0 || ifac_isprime(q))
{
avma = av2; return F;
}
setlg(E,l-1);
setlg(P,l-1);
if (cmpii(q, limit) > 0)
{
long l2 = expi(q)+1;
GEN P2 = coltrunc_init(l2);
GEN E2 = coltrunc_init(l2);
GEN F2 = mkmat2(P2,E2);
part = ifac_start(icopy(q), 0);
for(;;)
{
long e;
GEN p;
if (!ifac_next(&part,&p,&e)) break;
vectrunc_append(P2, p);
vectrunc_append(E2, utoipos(e));
q = diviiexact(q, powiu(p, e));
if (cmpii(q, limit) <= 0) break;
}
F2 = sort_factor(F2, (void*)&abscmpii, cmp_nodata);
F = merge_factor(F, F2, (void*)&abscmpii, cmp_nodata);
}
return gerepilecopy(av, F);
}
static void
matsmalltrunc_append(GEN m, ulong p, ulong e)
{
GEN P = gel(m,1), E = gel(m,2);
long l = lg(P);
P[l] = p; lg_increase(P);
E[l] = e; lg_increase(E);
}
static GEN
matsmalltrunc_init(long l)
{
GEN P = vecsmalltrunc_init(l);
GEN E = vecsmalltrunc_init(l); return mkvec2(P,E);
}
GEN
vecfactoru_i(ulong a, ulong b)
{
ulong N, k, p, n = b-a+1;
GEN v = const_vecsmall(n, 1);
GEN L = cgetg(n+1, t_VEC);
forprime_t T;
if (b < 510510UL) N = 7;
else if (b < 9699690UL) N = 8;
#ifdef LONG_IS_64BIT
else if (b < 223092870UL) N = 9;
else if (b < 6469693230UL) N = 10;
else if (b < 200560490130UL) N = 11;
else if (b < 7420738134810UL) N = 12;
else if (b < 304250263527210UL) N = 13;
else N = 16;
#else
else N = 9;
#endif
for (k = 1; k <= n; k++) gel(L,k) = matsmalltrunc_init(N);
u_forprime_init(&T, 2, usqrt(b));
while ((p = u_forprime_next(&T)))
{
ulong pk = p, K = ulogint(b, p);
for (k = 1; k <= K; k++)
{
ulong j, t = a / pk, ap = t * pk;
if (ap < a) { ap += pk; t++; }
for (j = ap-a+1; j <= n; j += pk, t++)
if (t % p) { v[j] *= pk; matsmalltrunc_append(gel(L,j), p,k); }
pk *= p;
}
}
for (k = 1, N = a; k <= n; k++, N++)
if (uel(v,k) != N) matsmalltrunc_append(gel(L,k), N/uel(v,k),1UL);
return L;
}
GEN
vecfactoru(ulong a, ulong b)
{
pari_sp av = avma;
return gerepilecopy(av, vecfactoru_i(a,b));
}
GEN
vecfactoroddu_i(ulong a, ulong b)
{
ulong N, k, p, n = ((b-a)>>1) + 1;
GEN v = const_vecsmall(n, 1);
GEN L = cgetg(n+1, t_VEC);
forprime_t T;
if (b < 255255UL) N = 6;
else if (b < 4849845UL) N = 7;
else if (b < 111546435UL) N = 8;
#ifdef LONG_IS_64BIT
else if (b < 3234846615UL) N = 9;
else if (b < 100280245065UL) N = 10;
else if (b < 3710369067405UL) N = 11;
else if (b < 152125131763605UL) N = 12;
else N = 16;
#else
else N = 9;
#endif
for (k = 1; k <= n; k++) gel(L,k) = matsmalltrunc_init(N);
u_forprime_init(&T, 3, usqrt(b));
while ((p = u_forprime_next(&T)))
{
ulong pk = p, K = ulogint(b, p);
for (k = 1; k <= K; k++)
{
ulong j, t = (a / pk) | 1UL, ap = t * pk;
if (ap < a) { ap += pk<<1; t+=2; }
for (j = ((ap-a)>>1)+1; j <= n; j += pk, t+=2)
if (t % p) { v[j] *= pk; matsmalltrunc_append(gel(L,j), p,k); }
pk *= p;
}
}
for (k = 1, N = a; k <= n; k++, N+=2)
if (uel(v,k) != N) matsmalltrunc_append(gel(L,k), N/uel(v,k),1UL);
return L;
}
GEN
vecfactoroddu(ulong a, ulong b)
{
pari_sp av = avma;
return gerepilecopy(av, vecfactoroddu_i(a,b));
}
GEN
vecfactorsquarefreeu(ulong a, ulong b)
{
ulong N, k, p, n = b-a+1;
GEN v = const_vecsmall(n, 1);
GEN L = cgetg(n+1, t_VEC);
forprime_t T;
if (b < 510510UL) N = 7;
else if (b < 9699690UL) N = 8;
#ifdef LONG_IS_64BIT
else if (b < 223092870UL) N = 9;
else if (b < 6469693230UL) N = 10;
else if (b < 200560490130UL) N = 11;
else if (b < 7420738134810UL) N = 12;
else if (b < 304250263527210UL) N = 13;
else N = 16;
#else
else N = 9;
#endif
for (k = 1; k <= n; k++) gel(L,k) = vecsmalltrunc_init(N);
u_forprime_init(&T, 2, usqrt(b));
while ((p = u_forprime_next(&T)))
{
ulong j, pk = p*p, t = a / pk, ap = t * pk;
if (ap < a) { ap += pk; t++; }
for (j = ap-a+1; j <= n; j += pk, t++) gel(L,j) = NULL;
t = a / p; ap = t * p;
if (ap < a) { ap += p; t++; }
for (j = ap-a+1; j <= n; j += p, t++)
if (gel(L,j)) { v[j] *= p; vecsmalltrunc_append(gel(L,j), p); }
}
for (k = 1, N = a; k <= n; k++, N++)
if (gel(L,k) && uel(v,k) != N) vecsmalltrunc_append(gel(L,k), N/uel(v,k));
return L;
}
GEN
vecsquarefreeu(ulong a, ulong b)
{
ulong j, k, p, n = b-a+1;
GEN L = const_vecsmall(n, 1);
forprime_t T;
u_forprime_init(&T, 2, usqrt(b));
while ((p = u_forprime_next(&T)))
{
ulong pk = p*p, t = a / pk, ap = t * pk;
if (ap < a) { ap += pk; t++; }
for (j = ap-a+1; j <= n; j += pk, t++) L[j] = 0;
}
for (k = j = 1; k <= n; k++)
if (L[k]) L[j++] = a+k-1;
setlg(L,j); return L;
}