-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patheratosthenes_sieve.cpp
executable file
·153 lines (114 loc) · 3.46 KB
/
eratosthenes_sieve.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
// Задача: реализовать алгоритм решета Эратосфена
// замерить скорость алгоритма и потребление памяти
// корректность работы сравнить по простому отпечатку
// реализовать оптимизацию по памяти с помощью битовой упаковки
// Задача: убрать дублирование кода, улучшить формат вывода
#include <ctime>
#include <cmath>
#include <vector>
#include <iostream>
const unsigned N = 1 << 31;
#define MB(bytes) (bytes >> 20)
#define LENGTH 80
#define OSTREAM std::cout
#define FINGERPRINT(getter) for (int i = 0; i < LENGTH; i++) { \
OSTREAM << (getter ? '1' : '0'); \
} OSTREAM << "\n";
// Признак простоты числа хранится в массиве для всех нечетных не больше N
// Индекс для доступа к массиву для числа n вычисляется так (n - 1) / 2
// Например числа 1, 3, 5 будут иметь индексы 0, 1, 2
// Тогда prime[5] содержит признак для числа 11
#define IDX(n) ((n - 1) / 2)
#define SIEVE_LOOP(N, TEST, SET) \
for (int x = 3; x < std::sqrt(N); x += 2) { if (TEST) \
for (int y = x*x; y <= N; y += 2*x) SET; }
unsigned sieve_with_vector()
{
std::vector<char> prime (N / 2 + 1, true);
prime[0] = false;
SIEVE_LOOP(N, prime[IDX(x)], prime[IDX(y)] = false)
FINGERPRINT(prime[i])
return prime.capacity(); // memory used (in bytes)
}
struct Bitset {
char *a;
unsigned sz;
Bitset(unsigned n):
a(0), sz(n / 8 + 1)
{
a = new char[sz];
std::memset(a, 0, sz);
}
~Bitset() {
delete [] a;
}
bool get(unsigned i) {
return (a[i >> 3] & (1u << (i % 8))) != 0;
}
void set(unsigned i, bool val) {
if (val)
a[i >> 3] |= 1u << (i % 8);
else
a[i >> 3] &= ~(1u << (i % 8));
}
unsigned size() { return sz * sizeof(char); }
void _all_ones() {
std::memset(a, ~0, sz * sizeof(char));
}
};
unsigned sieve_with_bitset()
{
Bitset prime (N / 2 + 1);
prime._all_ones();
prime.set(0, false);
SIEVE_LOOP(N, prime.get(IDX(x)), prime.set(IDX(y), false))
FINGERPRINT(prime.get(i))
return prime.size();
}
float clock_diff(time_t clock_time)
{
return (float) (clock() - clock_time) / CLOCKS_PER_SEC;
}
void proc_usage(const char *variant, float time)
{
OSTREAM << variant << ": " << time << " sec\n";
}
void memory_usage(unsigned bytes)
{
OSTREAM << "Memory: " << MB(bytes) << " MB\n";
}
void bench_eratosthenes_sieve(unsigned round)
{
time_t vector, bitset;
float v_time, b_time;
unsigned v_mem, b_mem;
OSTREAM << "Round " << round << ". Fingerprints:\n";
vector = clock();
v_mem = sieve_with_vector();
v_time = clock_diff(vector);
bitset = clock();
b_mem = sieve_with_bitset();
b_time = clock_diff(bitset);
OSTREAM << "\nResults:\n";
proc_usage("std::vector", v_time);
memory_usage(v_mem);
proc_usage("custom bitset", b_time);
memory_usage(b_mem);
OSTREAM << "\n";
}
#define BENCH_COUNT 2
int main()
{
OSTREAM << "Eratosthenes sieve: std::vector vs. custom bitset\n";
for (int i = 0; i < BENCH_COUNT; ++i) {
bench_eratosthenes_sieve(i + 1);
}
return 0;
}
/*
MacBook Pro Early 2011
2,3 GHz Intel Core i7
8 GB 1600 MHz DDR3
std::vector: 23.5223 sec
Bitset: 27.2006 sec
*/