forked from preda/gpuowl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPrimes.cpp
127 lines (111 loc) · 2.97 KB
/
Primes.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
#include "Primes.h"
#include <cassert>
#include <cstdio>
#include <algorithm>
static u32 pow32(u32 x, int n) {
u64 r = 1;
for (int i = 0; i < n; ++i) { r *= x; }
return r;
}
template<u32 P> static int order(u32 &x) { int c = 0; while (x % P == 0) { ++c; x /= P; }; return c; }
static int order(u32 &x, u32 P) { int c = 0; while (x % P == 0) { ++c; x /= P; }; return c; }
static u32 modExp2(u32 p, u32 e) {
u32 r = 2;
for (int i = 30 - __builtin_clz(e); i >= 0; --i) {
r = ((e & (1u << i)) ? 2u : 1u) * u64(r) * r % p;
}
return r;
}
Primes::Primes(u32 limit) :
limit(limit),
primeMap(limit/2)
{
primes.push_back(2);
primeMap[0] = true;
u32 last = 0;
while (true) {
u32 p = last + 1;
while (p < limit/2 && primeMap[p]) { ++p; }
u32 prime = 2 * p + 1;
if (prime >= limit) { break; }
primes.push_back(prime);
last = p;
u64 s = 2 * u64(p) * (p + 1);
for (u32 i = s; s < limit/2 && i < limit/2; i += prime) { primeMap[i] = true; }
}
primeMap.flip();
// fprintf(stderr, "Generated %lu primes: [%u, %u]\n", primes.size(), primes.front(), primes.back());
}
vector<pair<u32, u32>> Primes::factors(u32 x) {
vector<pair<u32, u32>> ret;
if (x <= 1) { return ret; }
if (isPrime(x)) { ret.push_back(make_pair(x, 1u)); return ret; }
if (int n = order<2>(x)) {
ret.push_back(make_pair(2, n));
if (isPrime(x)) { ret.push_back(make_pair(x, 1u)); return ret; }
if (x == 1) { return ret; }
}
if (int n = order<3>(x)) {
ret.push_back(make_pair(3, n));
if (isPrime(x)) { ret.push_back(make_pair(x, 1u)); return ret; }
if (x == 1) { return ret; }
}
if (int n = order<5>(x)) {
ret.push_back(make_pair(5, n));
if (isPrime(x)) { ret.push_back(make_pair(x, 1u)); return ret; }
if (x == 1) { return ret; }
}
for (auto p : from(7)) {
if (int n = order(x, p)) {
ret.push_back(make_pair(p, n));
if (isPrime(x)) { ret.push_back(make_pair(x, 1u)); return ret; }
if (x == 1) { return ret; }
}
}
// fprintf(stderr, "No factors for %u\n", x);
assert(false);
return ret;
}
vector<u32> Primes::divisors(u32 x) {
auto f = factors(x);
int nf = f.size();
vector<u32> divs;
vector<u32> count(nf);
while (true) {
int i = 0;
while (i < nf && count[i] == f[i].second) {
count[i] = 0;
++i;
}
if (i >= nf) { break; }
++count[i];
u32 d = 1;
for (int i = 0; i < nf; ++i) { d *= pow32(f[i].first, count[i]); }
divs.push_back(d);
}
sort(divs.begin(), divs.end());
return divs;
}
static void step(u32 p, u32 &d, u32 &r, u32 k) {
while (r % k == 0 && d != k && modExp2(p, d / k) == 1) { d /= k; r /= k; }
while (r % k == 0) { r /= k; }
}
u32 Primes::zn2(u32 p) {
u32 d = p - 1;
u32 r = d;
#define STEP(k) step(p, d, r, k);
STEP(2);
STEP(3);
STEP(5);
STEP(7);
STEP(11);
STEP(13);
for (u32 f : from(17)) {
if (r == 1) { return d; }
if (isPrime(r)) { break; }
STEP(f);
}
STEP(r);
#undef STEP
return d;
}