Tonelli-Shanks algorithm: Difference between revisions

m
→‎{{header|Phix}}: bigatom -> mpfr
m (Convert to a task.)
m (→‎{{header|Phix}}: bigatom -> mpfr)
Line 1,726:
=={{header|Phix}}==
{{trans|C#}}
{{libheader|mpfr}}
<lang Phix>include bigatommpfr.e
function ba_mod_exp(object base, exponent, modulus)
-- base/exponent/modulus can be integer/string/bigatom
function ts(objectstring nns, pps)
-- returns mod(power(base,exponent),modulus) [aka b^e%m], but in bigatoms and faster.
bigatommpz resn = BA_ONEmpz_init(ns),
base p = ba_modmpz_init(base,modulusps),
mt = impz_init(),
while ba_compare(exponent,0)!=0 do
ifr ba_mod(exponent,2)=BA_ONE thenmpz_init(),
respm1 = ba_modmpz_init(ba_multiply(res,base),modulus)
endpm2 if= mpz_init()
mpz_sub_ui(pm1,p,1) -- pm1 = p-1
base = ba_mod(ba_multiply(base,base),modulus)
mpz_fdiv_q_2exp(pm2,pm1,1) -- pm2 = pm1/2
exponent = ba_idivide(exponent,2)
mpz_powm(t,n,pm2,p) -- t = mod(n^pm2,p)
end while
if ba_mod_expmpz_cmp_si(nt,pm1o2, p1)!=BA_ONE0 then
return res
sol =return "No solution exitsexists"
end function
 
function ts(object n, p)
bigatom pm1 = ba_sub(p,1),
pm1o2 = ba_div(pm1,2)
if ba_mod_exp(n,pm1o2, p)!=BA_ONE then
return {0,0,false}
end if
bigatommpz q = mpz_init_set(pm1)
integer ss = 0
while ba_modmpz_even(q,2)=BA_ZERO do
ss += 1
mpz_fdiv_q_2exp(q,q,1) = ba_div( -- q,/=2)
end while
if ss=1 then
bigatom r1 = ba_mod_expmpz_add_ui(nt,ba_div(ba_add(p,1),4),p)
return {r1,ba_submpz_fdiv_q_2exp(pt,r1t,2),true}
mpz_powm(r,n,t,p) -- r = mod(n^((p+1)/4),p)
end if
integer z = 2else
mpz z = mpz_init(2)
while ba_mod_exp(z,pm1o2,p)!=pm1 do
zwhile +=true 1do
mpz_powm(t,z,pm2,p) -- t = mod(z^pm2,p)
end while
if mpz_cmp(t,pm1)=0 then exit end if
bigatom c = ba_mod_exp(z,q,p),
r = ba_mod_expmpz_add_ui(nz,ba_div(ba_add(qz,1),2),p), -- z+= 1
t = ba_mod_exp(n,q,p)
integer m = ss
while true do
if t=BA_ONE then
return {r,ba_sub(p,r),true}
end if
integer i = 0
bigatom zz = t
while zz!=BA_ONE and i<m-1 do
zz = ba_mod(ba_mul(zz,zz),p)
i += 1
end while
bigatommpz {b,c,zz} = cmpz_inits(3)
integermpz_powm(c,z,q,p) e = m-i-1 c = mod(z^q,p)
while e>0 dompz_add_ui(t,q,1)
b = ba_modmpz_fdiv_q_2exp(ba_mul(bt,b)t,p1)
mpz_powm(r,n,t,p) e -- r = mod(n^((q+1)/2),p)
mpz_powm(t,n,q,p) -- t = mod(n^q,p)
integer m = ss
while mpz_cmp_si(t,1) do -- t!=1
integer i = 0
pm1o2 = ba_divmpz_set(pm1zz,2t)
while mpz_cmp_si(zz,1)!=BA_ONE0 and i<m-1 do
mpz_powm_ui(zz,zz,2,p) -- zz = mod(zz^2,p)
i += 1
end while
mpz_set(b,c)
integer e = m-i-1
while truee>0 do
mpz_powm_ui(b,b,2,p) -- b = mod(b^2,p)
e -= 1
end while
t = ba_mod_expmpz_mul(nr,qr,pb)
mpz_mod(r,r,p) -- r = mod(r*b,p)
mpz_powm_ui(c,b,2,p) -- c = mod(b^2,p)
t = ba_mod(ba_mul mpz_mul(t,c)t,pc)
mpz_mod(t,t,p) -- t = mod(t*c,p)
end if m = i
end while
end if
r = ba_mod(ba_mul(r,b),p)
c = ba_modmpz_sub(ba_mul(b,b)p,p,r)
return mpz_get_str(r)&" and "&mpz_get_str(p)
t = ba_mod(ba_mul(t,c),p)
m = i
end while
end function
constant tests = {{"10","13"},
{"56","101"},
{"1030","10009"},
{"1032","10009"},
{"44402","100049"},
{"665820697","1000000009"},
{"881398088036","1000000000039"},
{"41660815127637347468140745042827704103445750172002",
ba_sprintsprintf(ba_add"1%s577",repeat(ba_power(10'0',50),57747))}} -- 10^50+577
 
for i=1 to length(tests) do
objectstring {p1,p2} = tests[i]
sequenceprintf(1,"For soln = %s and p = %s, %s\n",{p1,p2,ts(p1,p2)})
if not string(p1) then p1 = sprintf("%d",p1) end if
if not string(p2) then p2 = sprintf("%d",p2) end if
if sol[3] then
sol = ba_sprint(sol[1])&" and "&ba_sprint(sol[2])
else
sol = "No solution exits"
end if
printf(1,"For n = %s and p = %s, %s\n",{p1,p2,sol})
end for</lang>
{{out}}
Line 1,816 ⟶ 1,810:
For n = 56 and p = 101, 37 and 64
For n = 1030 and p = 10009, 1632 and 8377
For n = 1032 and p = 10009, No solution exitsexists
For n = 44402 and p = 100049, 30468 and 69581
For n = 665820697 and p = 1000000009, 378633312 and 621366697
7,806

edits