-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmiller-rabin.h
125 lines (98 loc) · 2.04 KB
/
miller-rabin.h
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
// Miller-Rabin primality test.
#ifndef _GOO_MILLER_RABIN_H
#define _GOO_MILLER_RABIN_H 1
#if __cplusplus > 201703L && __cpp_concepts >= 201907L
#include <concepts>
#include <cstdlib>
#include <ctime>
#include <numeric>
/* Returns true iff N is odd. */
template<std::integral I>
bool odd (I n)
{
return n & 1;
}
/* Returns true iff N is even. */
template<std::integral I>
bool even (I n)
{
return !(n & 1);
}
/* Modular exponentiation using exponentiation by squaring. B is the base,
E the exponent, and M the modulus. */
template<std::integral I>
I modular_pow (I b, I e, I m)
{
if (m == 1)
return 0;
I r = 1;
b %= m;
while (e > 0)
{
if (odd (e))
r = (r * b) % m;
e >>= 1;
b = (b * b) % m;
}
return r;
}
/* The Miller-Rabin test. */
template<std::integral I>
bool miller_rabin (I q, I k, I n)
{
/* Pick a random integer W in the range [2, n - 2]. */
I w = 2 + std::rand () % (n - 4);
/* w^q mod n */
I x = modular_pow (w, q, n);
if (x == 1 || x == n - 1)
return true;
for (I i = 1; i < k; ++i)
{
x = modular_pow (x, I(2), n);
if (x == n - 1)
return true;
if (x == 1)
return false;
}
/* N is composite. */
return false;
}
/* Return true if N is probably prime, and false if it definitely
is not. Uses the Miller-Rabin test. */
template<std::integral I>
bool prime_p (I n)
{
if (n == 2 || n == 3)
return true;
if (n < 2 || even (n))
return false;
/* Now n - 1 is even, we can write it as 2^k * q. */
I k = 0;
I q = n - 1;
while (even (q))
q /= 2, ++k;
/* Let's try it 4 times. */
for (int i = 0; i < 4; ++i)
if (!miller_rabin (q, k, n))
return false;
return true;
}
/* True iff A and B are coprimes. */
template<std::integral I>
bool coprime_p (I a, I b)
{
return std::gcd (a, b) == 1;
}
#if 0
int
main ()
{
std::srand (std::time (nullptr));
for (int i = 1; i < 102; ++i)
if (prime_p (i))
__builtin_printf ("%d ", i);
__builtin_printf ("\n");
}
#endif
#endif // C++20
#endif // _GOO_MILLER_RABIN_H