-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathNumberTheory.cpp
164 lines (141 loc) · 3.25 KB
/
NumberTheory.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
LL gcd(LL a, LL b)
{
if ( b == 0) return a;
return gcd( b, a % b);
}
LL coeffA, coeffB, G;
void extGcd(LL a, LL b)
{
if( b == 0 )
{
G = a;
coeffA = 1; coeffB = 0;
}
else
{
extGcd(b, a % b);
coeffA -= coeffB * (a/b);
swap(coeffA, coeffB);
}
}
/* If this system { x = r1 mod m1 ; x = r2 mod m2 } has a solution,
*this methods returns the smaLLest non negative solution.
* If there is no solution, -1 is returned.
*/
LL congruence( LL r1, LL m1, LL r2, LL m2)
{
extGcd(m1,m2);
if( (r1 - r2 ) % G != 0) return -1;
LL M = m1 * m2 / G; // Solution exists and is unique on LCM(m1,m2) = M
LL K = ( r2 - r1) / G;
LL ans = ((K * m1 * coeffA ) + r1) % M; // Note that K * (m1*coeffA + m2*coeffB) = r2-r1
if( ans < 0) ans += M;
return ans;
}
/* this function calculates (a*b)%c taking into account that a*b might overflow */
unsigned long long mulmod(unsigned long long a,unsigned long long b,unsigned long long c)
{
unsigned long long sum = 0,y = a % c;
while( b )
{
if(b & 1)
{
sum += y;
if( sum >= c)
sum -= c;
}
y+=y;
if(y>=c) y-=c;
b >>= 1;
}
return sum;
}
unsigned long long modulo(unsigned long long a, unsigned long long b, unsigned long long P)
{
unsigned long long ans = 1;
while( b )
{
if( b & 1 )
ans = mulmod(ans, a, P);
a = mulmod(a, a, P);
b >>= 1;
}
return ans;
}
const int maxIter = 5;
bool passesMiLLerRabin(unsigned long long N)
{
if(N < 2) return false;
if( N % 2 == 0) return N == 2;
if( N % 3 == 0) return N == 3;
if( N % 5 == 0) return N == 5;
if( N % 7 == 0) return N == 7;
int d = 0;
long long odd = N - 1;
while( (odd & 1) == 0)
{
d++;
odd>>= 1;
}
for(int i = 0; i < maxIter; i++)
{
long long a = rand() % ( N - 1) + 1; // a is random number from 1 to N -1
long long mod = modulo( a, odd, N);
bool passes = ( mod == 1 || mod == N -1 );
for(int r = 1; r < d && !passes; r ++)
{
mod = mulmod( mod, mod, N);
passes = passes || mod == N - 1;
}
if(!passes)
return false;
}
return true;
}
/* This is a pseudo random number genrator modulo n
*/
LL alpha, beta;
LL f(LL x, LL n)
{
LL temp = mulmod(x, x, n);
temp = mulmod( alpha, temp, n);
return ( temp + beta) % n;
}
/* Function returns a non trivial factor of the number N.
* Make sure before caLLing this that N is not a prime using miLLer rabin
*/
LL poLLardRho(LL N)
{
LL x, y, d;
while(true)
{
x = 2, y = 2, d = 1;
alpha = (rand() % (N -1)) + 1;
beta = (rand() % (N -1)) + 1;
while( d == 1)
{
x = f(x,N);
y = f( f(y,N), N);
d = gcd( abs(x - y), N);
}
if( d != N) break;
}
assert(N % d == 0); // if this assertion fails, consider increasing max iter and check if N is a prime
return d;
}
/* Function that returns a vector of prime factors of N in random order */
vector<LL> probabilisticFactorize(LL N)
{
vector<LL> factors;
while( N > 1 && !passesMiLLerRabin(N))
{
LL d = poLLardRho( N );
N = N / d;
vector<LL> f = probabilisticFactorize( d );
for(int i = 0; i < f.size(); i++)
factors.push_back( f[i]);
}
if( N > 1)
factors.push_back( N );
return factors;
}