September Morn Update

This commit is contained in:
Ingy döt Net 2019-09-12 10:33:56 -07:00
parent 4e2d22a71d
commit aac6731f2c
6856 changed files with 141342 additions and 21127 deletions

View 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;
}

View 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);
}

View file

@ -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"

View file

@ -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

View file

@ -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

View 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

View file

@ -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 nittygritty 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*/

View file

@ -0,0 +1,2 @@
say 37.znorder(1000) #=> 100
say 54.znorder(100001) #=> 9090