-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCoprimeSieve.h
92 lines (76 loc) · 2.97 KB
/
CoprimeSieve.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
#pragma once
#include <cstddef>
#include <concepts>
#include <iostream>
#include <memory>
#include <vector>
#include "BitArray.h"
// An Eratosthenes-type sieve to return all numbers in a given range coprime to a given list of obstructions.
template<std::unsigned_integral T>
class CoprimeSieve
{
private:
// The underlying bit array.
BitArray sieve;
// The inclusive lower bound on the numbers sieved.
T lowerLimit;
// The exclusive upper bound on the numbers sieved.
T upperLimit;
// The numbers in ['lowerLimit', 'upperLimit') coprime to every element of 'obstructions'.
std::shared_ptr<std::vector<T>> coprimes;
// The obstructions.
std::shared_ptr<const std::vector<T>> obstructions;
public:
// Constructs a CoprimeSieve over ['lowerLimit', 'upperLimit') with the given obstructions
// and optionally outputs progress to 'clog'.
CoprimeSieve
(
T lowerLimit,
T upperLimit,
std::shared_ptr<const std::vector<T>> obstructions,
bool verbose = false
)
: lowerLimit (lowerLimit),
upperLimit (upperLimit),
sieve (upperLimit - lowerLimit, true),
obstructions (obstructions)
{
if (verbose)
for (T obstruction : obstructions)
{
std::clog << "Striking out multiples of " << obstruction << "\n";
// Sieve out every multiple of 'obstruction' in the range ['lowerLimit', 'upperLimit').
T firstMultiple = ((lowerLimit + obstruction - 1) / obstruction) * obstruction;
for (T multiple = firstMultiple; multiple < upperLimit; multiple += obstruction)
sieve.Reset (multiple - lowerLimit);
}
else
for (T obstruction : obstructions)
{
T firstMultiple = ((lowerLimit + obstruction - 1) / obstruction) * obstruction;
// Sieve out every multiple of 'obstruction' in the range ['lowerLimit', 'upperLimit').
for (T multiple = firstMultiple; multiple < upperLimit; multiple += obstruction)
sieve.Reset (multiple - lowerLimit);
}
coprimes = std::make_shared<std::vector<T>> ();
for (T i = lowerLimit; i < upperLimit; ++i)
if (sieve.Get (i - lowerLimit))
coprimes->emplace_back (i);
}
// Returns the numbers in ['lowerLimit', 'upperLimit') coprime to every element of 'obstructions'.
std::shared_ptr<const std::vector<T>> Coprimes () const
{
return coprimes;
}
// Returns the number of numbers in ['lowerLimit', 'upperLimit') coprime to every element of 'obstructions'.
std::size_t Count () const
{
return coprimes->size ();
}
// Returns whether 'n' is coprime to every element of obstructions, if n is in ['lowerLimit', 'upperLimit').
// Out of range arguments result in undefined behaviour.
bool IsCoprime (T n) const
{
return sieve.Get (n - lowerLimit);
}
};