324 lines
5.8 KiB
Plaintext
324 lines
5.8 KiB
Plaintext
' ***********************************************
|
|
'subject: Shanks's square form factorization:
|
|
' ambiguous forms of discriminant 4N
|
|
' give factors of N.
|
|
'tested : FreeBasic 1.08.1
|
|
|
|
|
|
'------------------------------------------------
|
|
const MxN = culngint(1) shl 62
|
|
'input maximum
|
|
|
|
const qx = (1 shl 5) - 1
|
|
'queue size
|
|
|
|
type arg
|
|
'squfof arguments
|
|
as ulong m, f
|
|
as integer vb
|
|
end type
|
|
|
|
type bqf
|
|
declare sub rho ()
|
|
'reduce indefinite form
|
|
declare function issq (byref r as ulong) as integer
|
|
'return -1 if c is square, set r:= sqrt(c)
|
|
declare sub qform (byref g as string, byval t as integer)
|
|
'print binary quadratic form #t (a, 2b, c)
|
|
|
|
as ulong rN, a, b, c
|
|
as integer vb
|
|
end type
|
|
|
|
type queue
|
|
declare sub enq (byref P as bqf)
|
|
'enqueue P.c, P.b if appropriate
|
|
declare function pro (byref P as bqf, byval r as ulong) as integer
|
|
'return -1 if a proper square form is found
|
|
|
|
as ulong a(qx), L, m
|
|
as integer k, t
|
|
end type
|
|
|
|
'global variables
|
|
dim shared N as ulongint
|
|
'the number to split
|
|
|
|
dim shared flag as integer
|
|
'signal to end all threads
|
|
|
|
dim shared as ubyte q1024(1023), q3465(3464)
|
|
'quadratic residue tables
|
|
|
|
|
|
'------------------------------------------------
|
|
sub bqf.rho ()
|
|
dim as ulong q, t
|
|
swap a, c
|
|
'residue
|
|
q = culng(rN + b) \ a
|
|
t = b: b = q * a - b
|
|
'pseudo-square
|
|
c += q * (t - b)
|
|
end sub
|
|
|
|
'initialize form
|
|
#macro rhoin(F)
|
|
F.rho : h = F.b
|
|
F.c = (mN - h * h) \ F.a
|
|
#endmacro
|
|
|
|
function bqf.issq (byref r as ulong) as integer
|
|
if q1024(c and 1023) andalso q3465(c mod 3465) then
|
|
'98.6% non-squares filtered
|
|
r = culng(sqr(c))
|
|
if r * r = c then return -1
|
|
end if
|
|
issq = 0
|
|
end function
|
|
|
|
sub bqf.qform (byref g as string, byval t as integer)
|
|
if vb = 0 then exit sub
|
|
dim as longint u = a, v = b, w = c
|
|
if t and 1 then
|
|
w = -w
|
|
else
|
|
u = -u
|
|
end if
|
|
v shl= 1
|
|
print g;str(t);" = (";u;",";v;",";w;")"
|
|
end sub
|
|
|
|
'------------------------------------------------
|
|
#macro red(r, a)
|
|
r = iif(a and 1, a, a shr 1)
|
|
if m > 2 then
|
|
r = iif(r mod m, r, r \ m)
|
|
end if
|
|
#endmacro
|
|
|
|
sub queue.enq (byref P as bqf)
|
|
dim s as ulong
|
|
red(s, P.c)
|
|
if s < L then
|
|
'circular queue
|
|
k = (k + 2) and qx
|
|
if k > t then t = k
|
|
'enqueue P.b, P.c
|
|
a(k) = P.b mod s
|
|
a(k + 1) = s
|
|
end if
|
|
end sub
|
|
|
|
function queue.pro (byref P as bqf, byval r as ulong) as integer
|
|
dim as integer i, sw
|
|
'skip improper square forms
|
|
for i = 0 to t step 2
|
|
sw = (P.b - a(i)) mod r = 0
|
|
sw and= a(i + 1) = r
|
|
if sw then return 0
|
|
next i
|
|
pro = -1
|
|
end function
|
|
|
|
'------------------------------------------------
|
|
sub squfof (byval ap as any ptr)
|
|
dim as arg ptr rp = cptr(arg ptr, ap)
|
|
dim as ulong L2, m, r, t, f = 1
|
|
dim as integer ix, i, j
|
|
dim as ulongint mN, h
|
|
'principal and ambiguous cycles
|
|
dim as bqf P, A
|
|
dim Q as queue
|
|
|
|
if (N and 1) = 0 then
|
|
rp->f = 2 ' even N
|
|
flag =-1: exit sub
|
|
end if
|
|
|
|
h = culngint(sqr(N))
|
|
if h * h = N then
|
|
'N is square
|
|
rp->f = culng(h)
|
|
flag =-1: exit sub
|
|
end if
|
|
|
|
rp->f = 1
|
|
'multiplier
|
|
m = rp->m
|
|
if m > 1 then
|
|
if (N mod m) = 0 then
|
|
rp->f = m ' m | N
|
|
flag =-1: exit sub
|
|
end if
|
|
|
|
'check overflow m * N
|
|
if N > (MxN \ m) then exit sub
|
|
end if
|
|
mN = N * m
|
|
|
|
r = int(sqr(mN))
|
|
'float64 fix
|
|
if culngint(r) * r > mN then r -= 1
|
|
P.rN = r
|
|
A.rN = r
|
|
|
|
P.vb = rp->vb
|
|
A.vb = rp->vb
|
|
'verbosity switch
|
|
if P.vb then print "r = "; r
|
|
|
|
Q.k = -2: Q.t = -1: Q.m = m
|
|
'Queue entry bounds
|
|
Q.L = int(sqr(r * 2))
|
|
L2 = Q.L * m shl 1
|
|
|
|
'principal form
|
|
P.b = r: P.c = 1
|
|
rhoin(P)
|
|
P.qform("P", 1)
|
|
|
|
ix = Q.L shl 2
|
|
for i = 2 to ix
|
|
'search principal cycle
|
|
|
|
if P.c < L2 then Q.enq(P)
|
|
|
|
P.rho
|
|
if (i and 1) = 0 andalso P.issq(r) then
|
|
'square form found
|
|
|
|
if Q.pro(P, r) then
|
|
|
|
P.qform("P", i)
|
|
'inverse square root
|
|
A.b =-P.b: A.c = r
|
|
rhoin(A): j = 1
|
|
A.qform("A", j)
|
|
|
|
do
|
|
'search ambiguous cycle
|
|
t = A.b
|
|
A.rho: j += 1
|
|
|
|
if A.b = t then
|
|
'symmetry point
|
|
A.qform("A", j)
|
|
red(f, A.a)
|
|
if f = 1 then exit do
|
|
|
|
flag = -1
|
|
'factor found
|
|
end if
|
|
loop until flag
|
|
|
|
end if ' proper square
|
|
end if ' square form
|
|
|
|
if flag then exit for
|
|
next i
|
|
|
|
rp->f = f
|
|
end sub
|
|
|
|
'------------------------------------------------
|
|
data 2501
|
|
data 12851
|
|
data 13289
|
|
data 75301
|
|
data 120787
|
|
data 967009
|
|
data 997417
|
|
data 7091569
|
|
data 13290059
|
|
data 23515517
|
|
data 42854447
|
|
data 223553581
|
|
data 2027651281
|
|
data 11111111111
|
|
data 100895598169
|
|
data 1002742628021
|
|
data 60012462237239
|
|
data 287129523414791
|
|
data 9007199254740931
|
|
data 11111111111111111
|
|
data 314159265358979323
|
|
data 384307168202281507
|
|
data 419244183493398773
|
|
data 658812288346769681
|
|
data 922337203685477563
|
|
data 1000000000000000127
|
|
data 1152921505680588799
|
|
data 1537228672809128917
|
|
data 4611686018427387877
|
|
data 0
|
|
|
|
'main
|
|
'------------------------------------------------
|
|
const tx = 4
|
|
dim as double tim = timer
|
|
dim h(4) as any ptr
|
|
dim a(4) as arg
|
|
dim as ulongint f
|
|
dim as integer s, t
|
|
|
|
width 64, 30
|
|
cls
|
|
|
|
'tabulate quadratic residues
|
|
for t = 0 to 1540
|
|
s = t * t
|
|
q1024(s and 1023) =-1
|
|
q3465(s mod 3465) =-1
|
|
next t
|
|
|
|
a(0).vb = 0
|
|
'set one verbosity switch only
|
|
|
|
a(0).m = 1
|
|
'multipliers
|
|
a(1).m = 3
|
|
a(2).m = 5
|
|
a(3).m = 7
|
|
a(4).m = 11
|
|
|
|
do
|
|
print
|
|
|
|
do : read N
|
|
loop until N < MxN
|
|
if N < 2 then exit do
|
|
|
|
print "N = "; N
|
|
|
|
flag = 0
|
|
|
|
for t = 1 to tx + 1 step 2
|
|
if t < tx then
|
|
h(t) = threadcreate(@squfof, @a(t))
|
|
end if
|
|
|
|
squfof(@a(t - 1))
|
|
f = a(t - 1).f
|
|
|
|
if t < tx then
|
|
threadwait(h(t))
|
|
if f = 1 then f = a(t).f
|
|
end if
|
|
|
|
if f > 1 then exit for
|
|
next t
|
|
|
|
'assert
|
|
if N mod f then f = 1
|
|
|
|
if f = 1 then
|
|
print "fail"
|
|
else
|
|
print "f = ";f;" N/f = ";N \ f
|
|
end if
|
|
loop
|
|
|
|
print "total time:"; csng(timer - tim); " s"
|
|
end
|