Skip to content

Commit 8064cad

Browse files
committed
Added carmichael function
1 parent 9afa811 commit 8064cad

File tree

4 files changed

+314
-2
lines changed

4 files changed

+314
-2
lines changed

math/binary_gcd.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#include <bits/stdc++.h>
2+
3+
// important!
4+
#pragma GCC target("bmi")
5+
6+
template<typename T>
7+
T gcd(T a, T b) {
8+
auto ctz = [] (T const& x) { return __builtin_ctzll(x); };
9+
10+
int shift = ctz(a|b);
11+
b >>= ctz(b);
12+
13+
while (a) {
14+
a >>= ctz(a);
15+
if (a < b) std::swap(a, b);
16+
a -= b;
17+
}
18+
19+
return b << shift;
20+
}
21+
22+
int main() {
23+
using ll = uint64_t;
24+
25+
ll a, b;
26+
std::cin >> a >> b;
27+
28+
std::cout << gcd<ll>(a, b) << "\n";
29+
}

math/carmichael.cpp

Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
#include <bits/stdc++.h>
2+
3+
#include <bits/stdc++.h>
4+
5+
using namespace std;
6+
7+
using u128 = __uint128_t;
8+
using s128 = __int128_t;
9+
using u64 = uint64_t;
10+
11+
inline u128 mul(u128 x, u128 y, u128 c)
12+
{
13+
u128 ans = 0;
14+
static const u64 shift = 25;
15+
while (y) {
16+
ans += x*(y&((1<<shift)-1));
17+
x = (x<<shift)%c;
18+
y >>= shift;
19+
}
20+
return ans % c;
21+
}
22+
23+
u128 HI(u128 x) { return x>>64; };
24+
u128 LO(u128 x) { return u64(x); };
25+
26+
namespace Prime {
27+
28+
int const num_tries = 20;
29+
30+
u128 power(u128 a, u128 b, u128 c) {
31+
u128 ans = 1;
32+
while (b) {
33+
34+
if (b&1) ans = mul(ans, a, c);
35+
a = mul(a, a, c);
36+
b >>= 1;
37+
}
38+
return ans;
39+
}
40+
41+
bool witness(u128 base, u128 s, u128 d, u128 n) {
42+
u128 x = power(base, d, n);
43+
u128 y;
44+
while (s--) {
45+
46+
y = mul(x, x, n);
47+
if (y == 1 and x != 1 and x != n-1) return false;
48+
x = y;
49+
}
50+
if (x != 1) return false;
51+
return true;
52+
}
53+
54+
mt19937_64 rd;
55+
56+
bool is_prime(u128 x) {
57+
if (x == 2 or x == 3 or x == 1) return true;
58+
if (x % 2 == 0 or x % 3 == 0) return false;
59+
60+
u128 s = 1, d = x>>1;
61+
while (!(d&1)) s++, d>>= 1;
62+
63+
uniform_int_distribution<u64> rng(2, HI(x)? u64(-1ull): (u64(x)-1));
64+
65+
for (int i = 0; i < num_tries; i++) {
66+
u64 p = rng(rd);
67+
if (!witness(p, s, d, x)) return false;
68+
}
69+
return true;
70+
}
71+
} //end namespace Prime
72+
73+
namespace Factor {
74+
75+
int const num_tries = 10;
76+
77+
u128 n, niv_n;
78+
void setn(u128 n_) {
79+
// calculates multiplicative inverse of n mod 2^128
80+
// to use in modular reduction (how?)
81+
n = n_;
82+
niv_n = 1;
83+
u128 x = n;
84+
for (int i = 1; i <= 126; i++)
85+
{
86+
niv_n*=x;
87+
x*=x;
88+
}
89+
}
90+
91+
struct u256 {
92+
u128 hi, lo;
93+
94+
static u256 mul128(u128 x,u128 y) {
95+
u128 t1 = LO(x)*LO(y);
96+
u128 t2 = HI(x)*LO(y) + HI(y)*LO(x) + HI(t1);
97+
return { HI(x)*HI(y) + HI(t2) , (t2<<64) + LO(t1) };
98+
}
99+
};
100+
101+
u128 mmul(u128 x,u128 y) {
102+
u256 m = u256::mul128(x,y);
103+
// some kind of montgomery reduction?
104+
u128 ans = m.hi - u256::mul128(m.lo*niv_n, n).hi;
105+
if (s128(ans) < 0) ans += n;
106+
return ans;
107+
}
108+
109+
inline u128 f(u128 x, u128 inc) {
110+
return mmul(x, x) + inc;
111+
}
112+
113+
inline u128 gcd(u128 a, u128 b) {
114+
auto ctz = [] (u128 x) {
115+
if (!HI(x)) return __builtin_ctzll(x);
116+
return 64 + __builtin_ctzll(x>>64);
117+
};
118+
119+
int shift = ctz(a|b);
120+
b >>= ctz(b);
121+
while (a) {
122+
a >>= ctz(a);
123+
if (a < b) swap(a, b);
124+
a -= b;
125+
}
126+
return b << shift;
127+
}
128+
129+
inline u128 rho(u128 seed, u128 n, u64 inc) {
130+
static const int step=1<<9;
131+
132+
setn(n);
133+
134+
auto sub = [&] (u128 x, u128 y) { return x>y ? x-y:y-x; };
135+
136+
u128 y = f(seed, inc);
137+
138+
for (int l=1;; l<<=1)
139+
{
140+
u128 x = y;
141+
for (int i = 1; i <= l; i++) y = f(y, inc);
142+
for (int k = 0; k < l; k += step)
143+
{
144+
int d = min(step, l-k);
145+
u128 g = seed, y0 = y;
146+
147+
for (int i = 1; i <= d; i++) {
148+
y = f(y, inc);
149+
g = mmul(g, sub(x,y));
150+
}
151+
152+
g = gcd(g,n);
153+
154+
if (g==1) continue;
155+
if (g!=n) return g;
156+
157+
u128 y = y0;
158+
159+
while (gcd(sub(x,y), n) == 1) y = f(y, inc);
160+
161+
return gcd(sub(x,y), n) % n;
162+
}
163+
}
164+
return 0;
165+
}
166+
167+
mt19937_64 rd;
168+
169+
u128 rho(u128 x) {
170+
if (x <= 3) return 0;
171+
if (x%2 == 0) return 2;
172+
if (x%3 == 0) return 3;
173+
174+
uniform_int_distribution<u64> rng(2, HI(x)? u64(-1ull): (u64(x)-1));
175+
176+
for (u128 i = 2; i < num_tries; i++) {
177+
u128 ans = rho(rng(rd), x, i);
178+
if (ans != 0 and ans != x) return ans;
179+
}
180+
return 0;
181+
}
182+
183+
void factor(u128 x, vector<u128>& primes) {
184+
185+
if (Prime::is_prime(x)) primes.push_back(x);
186+
else {
187+
u128 fac = rho(x);
188+
factor(fac, primes);
189+
factor(x/fac, primes);
190+
}
191+
}
192+
193+
vector<u128> factor(u128 x) {
194+
vector<u128> v;
195+
factor(x, v);
196+
sort(v.begin(), v.end());
197+
return v;
198+
}
199+
200+
vector<pair<u128,u128>> factor_pairs(u128 x) {
201+
auto v = factor(x);
202+
vector<pair<u128, u128>> res;
203+
204+
for (int i = 0; i < (int)v.size(); i++) {
205+
if (i == 0 or res.back().first != v[i])
206+
res.emplace_back(v[i], 1);
207+
else
208+
res.back().second++;
209+
}
210+
return res;
211+
}
212+
} // end namespace Factor
213+
214+
template <typename T>
215+
void read(T &x)
216+
{
217+
#define gc (c=getchar())
218+
219+
char c;
220+
while(gc < '0');
221+
x = c - '0';
222+
while(gc >= '0') x = x*10 + c - '0';
223+
224+
#undef gc
225+
}
226+
227+
template <typename T>
228+
void write(T x, char c = '\n')
229+
{
230+
static char st[40];
231+
int top=0;
232+
do {st[++top] = '0' + x%10;} while (x /=10);
233+
do {putchar(st[top]);} while (--top);
234+
if (c != 0) putchar(c);
235+
}
236+
237+
template<typename T>
238+
T gcd(T a, T b) {
239+
if (b == 0) return a;
240+
return gcd(b, a%b);
241+
}
242+
243+
template<typename T>
244+
T lcm(T a, T b) {
245+
return a/gcd(a, b)*b;
246+
}
247+
248+
template<typename T>
249+
T power(T a, T b) {
250+
T ans = 1;
251+
while (b) {
252+
if (b&1) ans *= a;
253+
a *= a;
254+
b >>= 1;
255+
}
256+
return ans;
257+
}
258+
259+
template<typename T>
260+
T carmichael(pair<T, T> const& x) {
261+
T ans = power(x.first, x.second-1) * (x.first-1);
262+
return ans;
263+
}
264+
template<typename T>
265+
T carmichael(T x) {
266+
auto factors = Factor::factor_pairs(x);
267+
T ans = 1;
268+
269+
for (auto const& i : factors) {
270+
ans = lcm(ans, carmichael(i));
271+
}
272+
273+
return ans;
274+
}
275+
276+
int main() {
277+
u128 x;
278+
read(x);
279+
280+
write(carmichael(x));
281+
}

math/determinant.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ T determinant(std::vector<std::vector<T>> A) {
4747
std::swap(A[best], A[i]);
4848
}
4949

50+
if (A[i][i] == T()) {
51+
return T();
52+
}
53+
5054
ans *= T(A[i][i]);
5155
divide_row<T>(A[i], A[i][i]);
5256

math/pollard_rho.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,6 @@ int main()
120120
cin >> x;
121121

122122
vector<ll> fac;
123-
for (int i = 0; i < 100; i++)
124-
Factor::factor(fac, x), fac.clear();
125123

126124
Factor::factor(fac, x);
127125
for (ll i : fac) cout << i << " ";

0 commit comments

Comments
 (0)