Tonelli-Shanks algorithm: Difference between revisions
Content added Content deleted
Thundergnat (talk | contribs) m (Convert to a task.) |
m (→{{header|Phix}}: bigatom -> mpfr) |
||
Line 1,726: | Line 1,726: | ||
=={{header|Phix}}== |
=={{header|Phix}}== |
||
{{trans|C#}} |
{{trans|C#}} |
||
{{libheader|mpfr}} |
|||
<lang Phix>include |
<lang Phix>include mpfr.e |
||
function ba_mod_exp(object base, exponent, modulus) |
|||
-- base/exponent/modulus can be integer/string/bigatom |
|||
⚫ | |||
-- returns mod(power(base,exponent),modulus) [aka b^e%m], but in bigatoms and faster. |
|||
mpz n = mpz_init(ns), |
|||
p = mpz_init(ps), |
|||
⚫ | |||
while ba_compare(exponent,0)!=0 do |
|||
r = mpz_init(), |
|||
pm1 = mpz_init(), |
|||
pm2 = 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) |
|||
⚫ | |||
⚫ | |||
return res |
|||
⚫ | |||
end function |
|||
⚫ | |||
bigatom pm1 = ba_sub(p,1), |
|||
⚫ | |||
⚫ | |||
return {0,0,false} |
|||
end if |
end if |
||
mpz q = mpz_init_set(pm1) |
|||
integer ss = 0 |
integer ss = 0 |
||
while |
while mpz_even(q) do |
||
ss += 1 |
ss += 1 |
||
q |
mpz_fdiv_q_2exp(q,q,1) -- q/=2 |
||
end while |
end while |
||
if ss=1 then |
if ss=1 then |
||
mpz_add_ui(t,p,1) |
|||
mpz_fdiv_q_2exp(t,t,2) |
|||
mpz_powm(r,n,t,p) -- r = mod(n^((p+1)/4),p) |
|||
⚫ | |||
else |
|||
mpz z = mpz_init(2) |
|||
while ba_mod_exp(z,pm1o2,p)!=pm1 do |
|||
while true do |
|||
mpz_powm(t,z,pm2,p) -- t = mod(z^pm2,p) |
|||
⚫ | |||
if mpz_cmp(t,pm1)=0 then exit end if |
|||
bigatom c = ba_mod_exp(z,q,p), |
|||
mpz_add_ui(z,z,1) -- z+= 1 |
|||
⚫ | |||
⚫ | |||
⚫ | |||
if t=BA_ONE then |
|||
return {r,ba_sub(p,r),true} |
|||
⚫ | |||
⚫ | |||
bigatom zz = t |
|||
⚫ | |||
zz = ba_mod(ba_mul(zz,zz),p) |
|||
⚫ | |||
end while |
end while |
||
mpz {b,c,zz} = mpz_inits(3) |
|||
mpz_powm(c,z,q,p) -- c = mod(z^q,p) |
|||
mpz_add_ui(t,q,1) |
|||
mpz_fdiv_q_2exp(t,t,1) |
|||
mpz_powm(r,n,t,p) -- r = mod(n^((q+1)/2),p) |
|||
mpz_powm(t,n,q,p) -- t = mod(n^q,p) |
|||
⚫ | |||
while mpz_cmp_si(t,1) do -- t!=1 |
|||
⚫ | |||
⚫ | |||
⚫ | |||
mpz_powm_ui(zz,zz,2,p) -- zz = mod(zz^2,p) |
|||
⚫ | |||
⚫ | |||
mpz_set(b,c) |
|||
integer e = m-i-1 |
|||
⚫ | |||
mpz_powm_ui(b,b,2,p) -- b = mod(b^2,p) |
|||
e -= 1 |
|||
⚫ | |||
⚫ | |||
mpz_mod(r,r,p) -- r = mod(r*b,p) |
|||
mpz_powm_ui(c,b,2,p) -- c = mod(b^2,p) |
|||
⚫ | |||
mpz_mod(t,t,p) -- t = mod(t*c,p) |
|||
⚫ | |||
end while |
end while |
||
⚫ | |||
r = ba_mod(ba_mul(r,b),p) |
|||
mpz_sub(p,p,r) |
|||
return mpz_get_str(r)&" and "&mpz_get_str(p) |
|||
⚫ | |||
⚫ | |||
end while |
|||
end function |
end function |
||
constant tests = {{10,13}, |
constant tests = {{"10","13"}, |
||
{56,101}, |
{"56","101"}, |
||
{1030,10009}, |
{"1030","10009"}, |
||
{1032,10009}, |
{"1032","10009"}, |
||
{44402,100049}, |
{"44402","100049"}, |
||
{665820697,1000000009}, |
{"665820697","1000000009"}, |
||
{881398088036,1000000000039}, |
{"881398088036","1000000000039"}, |
||
{"41660815127637347468140745042827704103445750172002", |
{"41660815127637347468140745042827704103445750172002", |
||
sprintf("1%s577",repeat('0',47))}} -- 10^50+577 |
|||
for i=1 to length(tests) do |
for i=1 to length(tests) do |
||
string {p1,p2} = tests[i] |
|||
printf(1,"For n = %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 |
|||
⚫ | |||
end if |
|||
printf(1,"For n = %s and p = %s, %s\n",{p1,p2,sol}) |
|||
end for</lang> |
end for</lang> |
||
{{out}} |
{{out}} |
||
Line 1,816: | Line 1,810: | ||
For n = 56 and p = 101, 37 and 64 |
For n = 56 and p = 101, 37 and 64 |
||
For n = 1030 and p = 10009, 1632 and 8377 |
For n = 1030 and p = 10009, 1632 and 8377 |
||
For n = 1032 and p = 10009, No solution |
For n = 1032 and p = 10009, No solution exists |
||
For n = 44402 and p = 100049, 30468 and 69581 |
For n = 44402 and p = 100049, 30468 and 69581 |
||
For n = 665820697 and p = 1000000009, 378633312 and 621366697 |
For n = 665820697 and p = 1000000009, 378633312 and 621366697 |