September Morn Update
This commit is contained in:
parent
4e2d22a71d
commit
aac6731f2c
6856 changed files with 141342 additions and 21127 deletions
139
Task/Multiplicative-order/C++/multiplicative-order.cpp
Normal file
139
Task/Multiplicative-order/C++/multiplicative-order.cpp
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
#include <algorithm>
|
||||
#include <bitset>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
typedef unsigned long ulong;
|
||||
std::vector<ulong> primes;
|
||||
|
||||
typedef struct {
|
||||
ulong p, e;
|
||||
} prime_factor; /* prime, exponent */
|
||||
|
||||
void sieve() {
|
||||
/* 65536 = 2^16, so we can factor all 32 bit ints */
|
||||
constexpr int SIZE = 1 << 16;
|
||||
|
||||
std::bitset<SIZE> bits;
|
||||
bits.flip(); // set all bits
|
||||
bits.reset(0);
|
||||
bits.reset(1);
|
||||
for (int i = 0; i < 256; i++) {
|
||||
if (bits.test(i)) {
|
||||
for (int j = i * i; j < SIZE; j += i) {
|
||||
bits.reset(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* collect primes into a list. slightly faster this way if dealing with large numbers */
|
||||
for (int i = 0; i < SIZE; i++) {
|
||||
if (bits.test(i)) {
|
||||
primes.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto get_prime_factors(ulong n) {
|
||||
std::vector<prime_factor> lst;
|
||||
ulong e, p;
|
||||
|
||||
for (ulong i = 0; i < primes.size(); i++) {
|
||||
p = primes[i];
|
||||
if (p * p > n) break;
|
||||
for (e = 0; !(n % p); n /= p, e++);
|
||||
if (e) {
|
||||
lst.push_back({ p, e });
|
||||
}
|
||||
}
|
||||
|
||||
if (n != 1) {
|
||||
lst.push_back({ n, 1 });
|
||||
}
|
||||
return lst;
|
||||
}
|
||||
|
||||
auto get_factors(ulong n) {
|
||||
auto f = get_prime_factors(n);
|
||||
std::vector<ulong> lst{ 1 };
|
||||
|
||||
size_t len2 = 1;
|
||||
/* L = (1); L = (L, L * p**(1 .. e)) forall((p, e)) */
|
||||
for (size_t i = 0; i < f.size(); i++, len2 = lst.size()) {
|
||||
for (ulong j = 0, p = f[i].p; j < f[i].e; j++, p *= f[i].p) {
|
||||
for (size_t k = 0; k < len2; k++) {
|
||||
lst.push_back(lst[k] * p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(lst.begin(), lst.end());
|
||||
return lst;
|
||||
}
|
||||
|
||||
ulong mpow(ulong a, ulong p, ulong m) {
|
||||
ulong r = 1;
|
||||
while (p) {
|
||||
if (p & 1) {
|
||||
r = r * a % m;
|
||||
}
|
||||
a = a * a % m;
|
||||
p >>= 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
ulong ipow(ulong a, ulong p) {
|
||||
ulong r = 1;
|
||||
while (p) {
|
||||
if (p & 1) r *= a;
|
||||
a *= a;
|
||||
p >>= 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
ulong gcd(ulong m, ulong n) {
|
||||
ulong t;
|
||||
while (m) {
|
||||
t = m;
|
||||
m = n % m;
|
||||
n = t;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
ulong lcm(ulong m, ulong n) {
|
||||
ulong g = gcd(m, n);
|
||||
return m / g * n;
|
||||
}
|
||||
|
||||
ulong multi_order_p(ulong a, ulong p, ulong e) {
|
||||
ulong m = ipow(p, e);
|
||||
ulong t = m / p * (p - 1);
|
||||
auto fac = get_factors(t);
|
||||
for (size_t i = 0; i < fac.size(); i++) {
|
||||
if (mpow(a, fac[i], m) == 1) {
|
||||
return fac[i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ulong multi_order(ulong a, ulong m) {
|
||||
auto pf = get_prime_factors(m);
|
||||
ulong res = 1;
|
||||
for (size_t i = 0; i < pf.size(); i++) {
|
||||
res = lcm(res, multi_order_p(a, pf[i].p, pf[i].e));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int main() {
|
||||
sieve();
|
||||
|
||||
printf("%lu\n", multi_order(37, 1000)); // expect 100
|
||||
printf("%lu\n", multi_order(54, 100001)); // expect 9090
|
||||
|
||||
return 0;
|
||||
}
|
||||
156
Task/Multiplicative-order/D/multiplicative-order.d
Normal file
156
Task/Multiplicative-order/D/multiplicative-order.d
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
import std.bigint;
|
||||
import std.random;
|
||||
import std.stdio;
|
||||
|
||||
struct PExp {
|
||||
BigInt prime;
|
||||
int exp;
|
||||
}
|
||||
|
||||
BigInt gcd(BigInt x, BigInt y) {
|
||||
if (y == 0) {
|
||||
return x;
|
||||
}
|
||||
return gcd(y, x % y);
|
||||
}
|
||||
|
||||
/// https://en.wikipedia.org/wiki/Modular_exponentiation#Right-to-left_binary_method
|
||||
BigInt modPow(BigInt b, BigInt e, BigInt n) {
|
||||
if (n == 1) return BigInt(0);
|
||||
BigInt result = 1;
|
||||
b = b % n;
|
||||
while (e > 0) {
|
||||
if (e % 2 == 1) {
|
||||
result = (result * b) % n;
|
||||
}
|
||||
e >>= 1;
|
||||
b = (b*b) % n;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
BigInt pow(long b, long e) {
|
||||
return pow(BigInt(b), BigInt(e));
|
||||
}
|
||||
BigInt pow(BigInt b, BigInt e) {
|
||||
if (e == 0) {
|
||||
return BigInt(1);
|
||||
}
|
||||
|
||||
BigInt result = 1;
|
||||
while (e > 1) {
|
||||
if (e % 2 == 0) {
|
||||
b *= b;
|
||||
e /= 2;
|
||||
} else {
|
||||
result *= b;
|
||||
b *= b;
|
||||
e = (e - 1) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
return b * result;
|
||||
}
|
||||
|
||||
BigInt sqrt(BigInt self) {
|
||||
BigInt b = self;
|
||||
while (true) {
|
||||
BigInt a = b;
|
||||
b = self / a + a >> 1;
|
||||
if (b >= a) return a;
|
||||
}
|
||||
}
|
||||
|
||||
long bitLength(BigInt self) {
|
||||
BigInt bi = self;
|
||||
long length;
|
||||
while (bi != 0) {
|
||||
length++;
|
||||
bi >>= 1;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
PExp[] factor(BigInt n) {
|
||||
PExp[] pf;
|
||||
BigInt nn = n;
|
||||
int b = 0;
|
||||
int e = 1;
|
||||
while ((nn & e) == 0) {
|
||||
e <<= 1;
|
||||
b++;
|
||||
}
|
||||
if (b > 0) {
|
||||
nn = nn >> b;
|
||||
pf ~= PExp(BigInt(2), b);
|
||||
}
|
||||
BigInt s = nn.sqrt();
|
||||
BigInt d = 3;
|
||||
while (nn > 1) {
|
||||
if (d > s) d = nn;
|
||||
e = 0;
|
||||
while (true) {
|
||||
BigInt div, rem;
|
||||
nn.divMod(d, div, rem);
|
||||
if (rem.bitLength > 0) break;
|
||||
nn = div;
|
||||
e++;
|
||||
}
|
||||
if (e > 0) {
|
||||
pf ~= PExp(d, e);
|
||||
s = nn.sqrt();
|
||||
}
|
||||
d += 2;
|
||||
}
|
||||
|
||||
return pf;
|
||||
}
|
||||
|
||||
BigInt moBachShallit58(BigInt a, BigInt n, PExp[] pf) {
|
||||
BigInt n1 = n - 1;
|
||||
BigInt mo = 1;
|
||||
foreach(pe; pf) {
|
||||
BigInt y = n1 / pe.prime.pow(BigInt(pe.exp));
|
||||
int o = 0;
|
||||
BigInt x = a.modPow(y, n);
|
||||
while (x > 1) {
|
||||
x = x.modPow(pe.prime, n);
|
||||
o++;
|
||||
}
|
||||
BigInt o1 = pe.prime.pow(BigInt(o));
|
||||
o1 = o1 / gcd(mo, o1);
|
||||
mo = mo * o1;
|
||||
}
|
||||
return mo;
|
||||
}
|
||||
|
||||
void moTest(ulong a, ulong n) {
|
||||
moTest(BigInt(a), n);
|
||||
}
|
||||
void moTest(BigInt a, ulong n) {
|
||||
// Commented out because the implementations tried all failed for the -2 and -3 tests.
|
||||
// if (!n.isProbablePrime()) {
|
||||
// writeln("Not computed. Modulus must be prime for this algorithm.");
|
||||
// return;
|
||||
// }
|
||||
if (a.bitLength < 100) {
|
||||
write("ord(", a, ")");
|
||||
} else {
|
||||
write("ord([big])");
|
||||
}
|
||||
write(" mod ", n, " ");
|
||||
BigInt nn = n;
|
||||
BigInt mob = moBachShallit58(a, nn, factor(nn - 1));
|
||||
writeln("= ", mob);
|
||||
}
|
||||
|
||||
void main() {
|
||||
moTest(37, 3343);
|
||||
|
||||
moTest(pow(10, 100) + 1, 7919);
|
||||
moTest(pow(10, 1000) + 1, 15485863);
|
||||
moTest(pow(10, 10000) - 1, 22801763489);
|
||||
|
||||
moTest(1511678068, 7379191741);
|
||||
moTest(3047753288, 2257683301);
|
||||
}
|
||||
|
|
@ -1 +1,15 @@
|
|||
primeFacsExp :: Integer -> [(Integer, Int)]
|
||||
powerMod
|
||||
:: (Integral a, Integral b)
|
||||
=> a -> a -> b -> a
|
||||
powerMod m _ 0 = 1
|
||||
powerMod m x n
|
||||
| n > 0 = f x_ (n - 1) x_
|
||||
where
|
||||
x_ = x `rem` m
|
||||
f _ 0 y = y
|
||||
f a d y = g a d
|
||||
where
|
||||
g b i
|
||||
| even i = g (b * b `rem` m) (i `quot` 2)
|
||||
| otherwise = f b (i - 1) (b * y `rem` m)
|
||||
powerMod m _ _ = error "powerMod: negative exponent"
|
||||
|
|
|
|||
|
|
@ -1,9 +1,17 @@
|
|||
powerMod :: (Integral a, Integral b) => a -> a -> b -> a
|
||||
powerMod m _ 0 = 1
|
||||
powerMod m x n | n > 0 = f x' (n-1) x' where
|
||||
x' = x `rem` m
|
||||
f _ 0 y = y
|
||||
f a d y = g a d where
|
||||
g b i | even i = g (b*b `rem` m) (i `quot` 2)
|
||||
| otherwise = f b (i-1) (b*y `rem` m)
|
||||
powerMod m _ _ = error "powerMod: negative exponent"
|
||||
import Data.List (foldl1') --'
|
||||
|
||||
foldl1_ = foldl1' --'
|
||||
|
||||
multOrder a m
|
||||
| gcd a m /= 1 = error "Arguments not coprime"
|
||||
| otherwise = foldl1_ lcm $ map (multOrder_ a) $ primeFacsExp m
|
||||
|
||||
multOrder_ a (p, k) = r
|
||||
where
|
||||
pk = p ^ k
|
||||
t = (p - 1) * p ^ (k - 1) -- totient \Phi(p^k)
|
||||
r = product $ map find_qd $ primeFacsExp t
|
||||
find_qd (q, e) = q ^ d
|
||||
where
|
||||
x = powerMod pk a (t `div` (q ^ e))
|
||||
d = length $ takeWhile (/= 1) $ iterate (\y -> powerMod pk y q) x
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
using Primes
|
||||
|
||||
function factors(n)
|
||||
f = [one(n)]
|
||||
for (p,e) in factor(n)
|
||||
f = reduce(vcat, f, [f*p^j for j in 1:e])
|
||||
f = reduce(vcat, [f*p^j for j in 1:e], init=f)
|
||||
end
|
||||
return length(f) == 1 ? [one(n), n] : sort!(f)
|
||||
end
|
||||
|
|
|
|||
113
Task/Multiplicative-order/Phix/multiplicative-order.phix
Normal file
113
Task/Multiplicative-order/Phix/multiplicative-order.phix
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
include mpfr.e
|
||||
|
||||
procedure multi_order(mpz res, a, sequence p_and_k)
|
||||
mpz pk = mpz_init(),
|
||||
t = mpz_init(),
|
||||
x = mpz_init(),
|
||||
q = mpz_init()
|
||||
mpz_set_si(res,1)
|
||||
if length(p_and_k)=1 then
|
||||
string {ps} = p_and_k
|
||||
mpz_set_str(pk,ps)
|
||||
mpz_sub_ui(t,pk,1)
|
||||
else
|
||||
atom {p, k} = p_and_k
|
||||
mpz_ui_pow_ui(pk,p,k)
|
||||
mpz_ui_pow_ui(t,p,k-1)
|
||||
mpz_mul_si(t,t,p-1)
|
||||
end if
|
||||
sequence pf = mpz_prime_factors(t)
|
||||
for i=1 to length(pf) do
|
||||
if length(pf[i])=1 then
|
||||
string {fs} = pf[i]
|
||||
mpz_set_str(q,fs)
|
||||
mpz_set(x,q)
|
||||
else
|
||||
{integer qi, integer ei} = pf[i]
|
||||
mpz_set_si(q,qi)
|
||||
mpz_pow_ui(x,q,ei)
|
||||
end if
|
||||
mpz_fdiv_q(x, t, x)
|
||||
mpz_powm(x,a,x,pk)
|
||||
integer guard = 0
|
||||
while mpz_cmp_si(x,1)!=0 do
|
||||
mpz_mul(res,res,q)
|
||||
mpz_powm(x,x,q,pk)
|
||||
guard += 1
|
||||
if guard>100 then ?9/0 end if -- (increase if rqd)
|
||||
end while
|
||||
end for
|
||||
x = mpz_free(x)
|
||||
end procedure
|
||||
|
||||
function multiplicative_order(mpz a, m)
|
||||
mpz res = mpz_init(1),
|
||||
ri = mpz_init()
|
||||
mpz_gcd(ri,a,m)
|
||||
if mpz_cmp_si(ri,1)!=0 then return "(a,m) not coprime" end if
|
||||
sequence pf = mpz_prime_factors(m,10000) -- (increase if rqd)
|
||||
for i=1 to length(pf) do
|
||||
multi_order(ri,a,pf[i])
|
||||
mpz_lcm(res,res,ri)
|
||||
end for
|
||||
return mpz_get_str(res)
|
||||
end function
|
||||
|
||||
function shorta(mpz n)
|
||||
string res = mpz_get_str(n)
|
||||
integer lr = length(res)
|
||||
if lr>80 then
|
||||
res[6..-6] = "..."
|
||||
res &= sprintf(" (%d digits)",lr)
|
||||
end if
|
||||
return res
|
||||
end function
|
||||
|
||||
procedure mo_test(mpz a, n)
|
||||
string res = multiplicative_order(a, n)
|
||||
printf(1,"ord(%s) mod %s = %s\n",{shorta(a),shorta(n),res})
|
||||
end procedure
|
||||
|
||||
function i(atom i) return mpz_init(i) end function -- (ugh)
|
||||
function p10(integer e,i) -- init to 10^e+i
|
||||
mpz res = mpz_init()
|
||||
mpz_ui_pow_ui(res,10,e)
|
||||
mpz_add_si(res,res,i)
|
||||
return res
|
||||
end function
|
||||
|
||||
atom t = time()
|
||||
mo_test(i(3), i(10))
|
||||
mo_test(i(37), i(1000))
|
||||
mo_test(i(37), i(10000))
|
||||
mo_test(i(37), i(3343))
|
||||
mo_test(i(37), i(3344))
|
||||
mo_test(i(2), i(1000))
|
||||
mo_test(p10(100,+1), i(7919))
|
||||
mo_test(p10(1000,+1), i(15485863))
|
||||
mo_test(p10(10000,-1), i(22801763489))
|
||||
mo_test(i(1511678068), i(7379191741))
|
||||
mo_test(i(3047753288), i(2257683301))
|
||||
?"==="
|
||||
mpz b = p10(20,-1)
|
||||
mo_test(i(2), b)
|
||||
mo_test(i(17),b)
|
||||
mo_test(i(54),i(100001))
|
||||
string s9090 = multiplicative_order(mpz_init(54),mpz_init(100001))
|
||||
if s9090!="9090" then ?9/0 end if
|
||||
mpz m54 = mpz_init(54),
|
||||
m100001 = mpz_init(100001)
|
||||
mpz_powm_ui(b,m54,9090,m100001)
|
||||
printf(1,"%s\n",mpz_get_str(b))
|
||||
bool error = false
|
||||
for r=1 to 9090-1 do
|
||||
mpz_powm_ui(b,m54,r,m100001)
|
||||
if mpz_cmp_si(b,1)=0 then
|
||||
printf(1,"mpz_powm_ui(54,%d,100001) gives 1!\n",r)
|
||||
error = true
|
||||
exit
|
||||
end if
|
||||
end for
|
||||
if not error then
|
||||
printf(1,"Everything checks. (%s)\n",{elapsed(time()-t)})
|
||||
end if
|
||||
|
|
@ -1,25 +1,26 @@
|
|||
/*REXX pgm computes multiplicative order of a minimum integer N such that a^n mod m≡1*/
|
||||
wa=0; wm=0 /* ═a═ ══m══ */ /*maximum widths of the A and M values.*/
|
||||
@.=.; @.1= 3 10
|
||||
@.2= 37 1000
|
||||
@.3= 37 10000
|
||||
@.4= 37 3343
|
||||
@.5= 37 3344
|
||||
@.6= 2 1000
|
||||
pad=left('',9)
|
||||
d=100 /*use 100 decimal digits for a starter.*/
|
||||
wa= 0; wm= 0 /* ═a═ ══m══ */ /*maximum widths of the A and M values.*/
|
||||
@.=.; @.1= 3 10
|
||||
@.2= 37 1000
|
||||
@.3= 37 10000
|
||||
@.4= 37 3343
|
||||
@.5= 37 3344
|
||||
@.6= 2 1000
|
||||
pad= left('', 9)
|
||||
d= 500 /*use 500 decimal digits for a starter.*/
|
||||
do w=1 for 2 /*when W≡1, find max widths of A and M.*/
|
||||
do j=1 while @.j\==.; parse var @.j a . 1 r m , n
|
||||
if w==1 then do; wa=max(wa, length(a)); wm=max(wm, length(m)); iterate; end
|
||||
if m//a==0 then n= ' [solution not possible]' /*test co-prime for A and B. */
|
||||
do j=1 while @.j\==.; parse var @.j a . 1 r m , n
|
||||
if w==1 then do; wa= max(wa, length(a) ); wm= max(wm, length(m) ); iterate
|
||||
end
|
||||
if m//a==0 then n= ' [solution not possible]' /*test co─prime for A and B. */
|
||||
numeric digits d /*start with 100 decimal digits. */
|
||||
if n=='' then do n=2; p=r*a /*compute product──may have an exponent*/
|
||||
if n=='' then do n= 2; p= r * a /*compute product──may have an exponent*/
|
||||
parse var p 'E' _ /*try to extract the exponent from P. */
|
||||
if _\=='' then do; numeric digits _+d /*bump the decimal digs.*/
|
||||
p=r*a /*recalculate integer P.*/
|
||||
end
|
||||
if p//m==1 then leave /*now, perform the nitty-gritty modulo.*/
|
||||
r=p /*assign product to R for next mult. */
|
||||
if p//m==1 then leave /*now, perform the nitty─gritty modulo.*/
|
||||
r= p /*assign product to R for next multiply*/
|
||||
end /*n*/ /* [↑] // is really ÷ remainder.*/
|
||||
say pad 'a=' right(a,wa) pad "m=" right(m,wm) pad 'multiplicative order:' n
|
||||
end /*j*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
say 37.znorder(1000) #=> 100
|
||||
say 54.znorder(100001) #=> 9090
|
||||
Loading…
Add table
Add a link
Reference in a new issue