Multiplicative order: Difference between revisions

Content added Content deleted
Line 1,374: Line 1,374:
ok 10 - mo(17,10**20-1) == 1499522760
ok 10 - mo(17,10**20-1) == 1499522760
ok 11 - mo(54,100001) == 9090</pre>
ok 11 - mo(54,100001) == 9090</pre>

=={{header|Phix}}==
{{trans|Ruby}}
Note this is considerably slower than Ruby, which completes in a fraction of a second, mainly I suspect
due to the fact that bigatom.e operates on a digit-by-digit basis.

Also, ba_mod_exp is fairly likely to get added to bigatom.e in a future release, likewise
the other ba_xxx routines below have been earmarked for possible inclusion.
<lang Phix>include bigatom.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.
bigatom res = BA_ONE
base = ba_mod(base,modulus)
while ba_compare(exponent,0)!=0 do
if ba_mod(exponent,2)=BA_ONE then
res = ba_mod(ba_multiply(res,base),modulus)
end if
base = ba_mod(ba_multiply(base,base),modulus)
exponent = ba_idivide(exponent,2)
end while
return res
end function

function ba_factor(object n)
-- eg ba_factor(1000) -> {{2,3},{5,3}}, ie power(2,3)*power(5,3) == 8*125 == 1000.
-- (note that each res[i] is {bigatom,integer})
if ba_compare(n,BA_ZERO)=0 then return {} end if
sequence pf = {}
integer e = 0
while ba_mod(n,2)=BA_ZERO do
n = ba_idivide(n,2)
e += 1
end while
if e>0 then
pf = {{2,e}}
end if
bigatom s = ba_sqrt(n),
d = ba_new(3)
while ba_compare(n,BA_ONE)>0 do
if ba_compare(d,s)>0 then
d = ba_new(n)
end if
e = 0
while true do
bigatom r = ba_mod(n,d)
if r!=BA_ZERO then exit end if
n = ba_idivide(n,d)
e += 1
end while
if e>0 then
pf = append(pf,{d,e})
s = ba_sqrt(n)
end if
d = ba_add(d,2)
end while
return pf
end function

function ba_gcd(object m, n)
while ba_compare(n,BA_ZERO)!=0 do
{m,n} = {n,ba_mod(m,n)}
end while
return m
end function

function ba_lcm(object m, n)
return ba_mul(ba_idivide(m,ba_gcd(m,n)),n)
end function

function multi_order(object a, sequence p_and_k)
{object p, integer k} = p_and_k
bigatom pk = ba_power(p,k),
t = ba_mul(ba_sub(p,1),ba_power(p,ba_sub(k,1))),
r = BA_ONE
sequence pf = ba_factor(t)
for i=1 to length(pf) do
{object q, integer e} = pf[i]
bigatom x = ba_mod_exp(a,ba_idiv(t,ba_power(q,e)),pk)
--
-- previous attempts at this task resulted in an infinite loop,
-- so I added a quard; feel free to increase limit as needed.
--
integer guard = 0
while x!=BA_ONE do
r = ba_mul(r,q)
x = ba_mod_exp(x,q,pk)
guard += 1
if guard>100 then ?9/0 end if
end while
end for
return r
end function
function multiplicative_order(object a, m)
if ba_gcd(a,m)!=BA_ONE then return "(a,m) not coprime" end if
sequence pf = ba_factor(m)
bigatom res = BA_ONE
for i=1 to length(pf) do
res = ba_lcm(res,multi_order(a,pf[i]))
end for
return res
end function

constant b100 = ba_power(2,100)

function shorta(object n)
return iff(ba_compare(n,b100)>0?"[big]":ba_sprint(n))
end function

procedure mo_test(object a, n)
string res = ba_sprint(multiplicative_order(a, n))
printf(1,"ord(%s) mod %s = %s\n",{shorta(a),shorta(n),res})
end procedure

atom t = time()
mo_test(37, 1000)
mo_test(37, 3343)
mo_test(ba_add(ba_power(10,100),1), 7919)
mo_test(ba_add(ba_power(10,1000),1), 15485863)
mo_test(ba_sub(ba_power(10,10000),1), 22801763489)
mo_test(1511678068, 7379191741)
mo_test(3047753288, 2257683301)
?"==="
bigatom b = ba_sub(ba_power(10,20),1)
mo_test(2, b)
mo_test(17,b)
mo_test(54,100001)
--/*
-- this all works fine, but doubles the runtime...
bigatom b9090 = multiplicative_order(54,100001)
ba_printf(1,"%B\n",b9090)
if ba_compare(b9090,9090)!=0 then ?9/0 end if
ba_printf(1,"%B\n",ba_mod_exp(54,b9090,100001))
bool error = false
atom t1 = time()+1
for r=1 to 9090-1 do
if ba_compare(ba_mod_exp(54,r,100001),1)=0 then
printf(1,"ba_mod_exp(54,%d,100001) gives 1!\n",r)
error = true
exit
end if
if time()>t1 then
printf(1,"checking %d...\r",r)
t1 = time()+1
end if
end for
if not error then puts(1,"Everything checks.\n") end if
--*/
?elapsed(time()-t)</lang>
{{out}}
<pre>
ord(37) mod 1000 = 100
ord(37) mod 3343 = 1114
ord([big]) mod 7919 = 3959
ord([big]) mod 15485863 = 15485862
ord([big]) mod 22801763489 = 22801763488
ord(1511678068) mod 7379191741 = 614932645
ord(3047753288) mod 2257683301 = 62713425
"==="
ord(2) mod 99999999999999999999 = 3748806900
ord(17) mod 99999999999999999999 = 1499522760
ord(54) mod 100001 = 9090
"1 minute and 11s"
</pre>


=={{header|Python}}==
=={{header|Python}}==