-
Notifications
You must be signed in to change notification settings - Fork 14
/
Gaussian_primes.cpp
132 lines (118 loc) · 3.77 KB
/
Gaussian_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
128
129
130
131
132
// Copyright (c) 2013 Elements of Programming Interviews. All rights reserved.
#include <algorithm>
#include <cassert>
#include <cmath>
#include <complex>
#include <iostream>
#include <random>
#include <set>
#include <vector>
using std::complex;
using std::cout;
using std::default_random_engine;
using std::endl;
using std::random_device;
using std::set;
using std::uniform_int_distribution;
using std::vector;
bool is_unit(const complex<int>& z);
// @include
struct ComplexCompare {
bool operator()(const complex<double>& lhs, const complex<double>& rhs) {
if (norm(lhs) != norm(rhs)) {
return norm(lhs) < norm(rhs);
} else if (lhs.real() != rhs.real()) {
return lhs.real() < rhs.real();
} else {
return lhs.imag() < rhs.imag();
}
}
};
vector<complex<int>> generate_Gaussian_primes(int n) {
set<complex<double>, ComplexCompare> candidates;
vector<complex<int>> primes;
// Generate all possible Gaussian prime candidates.
for (int i = -n; i <= n; ++i) {
for (int j = -n; j <= n; ++j) {
if (!is_unit({i, j}) && abs(complex<double>(i, j)) != 0) {
candidates.emplace(i, j);
}
}
}
while (!candidates.empty()) {
complex<double> p = *(candidates.begin());
candidates.erase(candidates.begin());
primes.emplace_back(p);
int max_multiplier = ceil(sqrt(2.0) * n / floor(sqrt(norm(p))));
// Any Gaussian integer outside the range we're iterating
// over below has a modulus greater than max_multiplier.
for (int i = max_multiplier; i >= -max_multiplier; --i) {
for (int j = max_multiplier; j >= -max_multiplier; --j) {
complex<double> x = {i, j};
if (floor(sqrt(norm(x))) > max_multiplier) {
// Skip multipliers whose modulus exceeds max_multiplier.
continue;
}
if (!is_unit(x)) {
candidates.erase(x * p);
}
}
}
}
return primes;
}
bool is_unit(const complex<int>& z) {
return (z.real() == 1 && z.imag() == 0) ||
(z.real() == -1 && z.imag() == 0) ||
(z.real() == 0 && z.imag() == 1) ||
(z.real() == 0 && z.imag() == -1);
}
// @exclude
vector<complex<int>> generate_Gaussian_primes_canary(int n) {
set<complex<double>, ComplexCompare> candidates;
vector<complex<int>> primes;
// Generate all possible Gaussian prime candidates.
for (int i = -n; i <= n; ++i) {
for (int j = -n; j <= n; ++j) {
if (!is_unit({i, j}) && abs(complex<double>(i, j)) != 0) {
candidates.emplace(i, j);
}
}
}
while (!candidates.empty()) {
complex<double> p = *(candidates.begin());
candidates.erase(candidates.begin());
primes.emplace_back(p);
int max_multiplier = n;
for (int i = max_multiplier; i >= -max_multiplier; --i) {
for (int j = max_multiplier; j >= -max_multiplier; --j) {
complex<double> x = {i, j};
if (!is_unit(x)) {
candidates.erase(x * p);
}
}
}
}
return primes;
}
int main(int argc, char* argv[]) {
default_random_engine gen((random_device())());
for (int i = 1; i <= 100; ++i) {
cout << "i = " << i << endl;
vector<complex<int>> first = generate_Gaussian_primes_canary(i);
vector<complex<int>> g_primes = generate_Gaussian_primes(i);
cout << first.size() << " " << g_primes.size() << endl;
for (int i = 0; i < first.size(); ++i) {
if (first[i].real() != g_primes[i].real() ||
first[i].imag() != g_primes[i].imag()) {
cout << "(" << first[i].real() << "," << first[i].imag() << ") ";
cout << "(" << g_primes[i].real() << "," << g_primes[i].imag() << ") ";
}
}
for (int i = first.size(); i < g_primes.size(); ++i) {
cout << "(" << g_primes[i].real() << "," << g_primes[i].imag() << ") ";
}
assert(first.size() == g_primes.size());
}
return 0;
}