qxLib
prime.inl
Go to the documentation of this file.
1 /**
2 
3  @file prime.inl
4  @author Khrapov
5  @date 6.10.2026
6  @copyright (c) Nick Khrapov, 2026. All right reserved.
7 
8 **/
9 
10 namespace qx
11 {
12 
13 namespace details
14 {
15 
16 // Operands must be smaller than the nonzero modulus; avoid overflowing their sum.
17 constexpr size_t prime_add_mod(size_t a, size_t b, size_t nModulus) noexcept
18 {
19  return a >= nModulus - b ? a - (nModulus - b) : a + b;
20 }
21 
22 constexpr size_t prime_multiply_mod(size_t a, size_t b, size_t nModulus) noexcept
23 {
24  size_t nResult = 0;
25  while (b != 0)
26  {
27  if (b & 1)
28  nResult = prime_add_mod(nResult, a, nModulus);
29  b >>= 1;
30  a = prime_add_mod(a, a, nModulus);
31  }
32  return nResult;
33 }
34 
35 constexpr size_t prime_power_mod(size_t nBase, size_t nExponent, size_t nModulus) noexcept
36 {
37  nBase %= nModulus;
38  size_t nResult = 1;
39  while (nExponent != 0)
40  {
41  if (nExponent & 1)
42  nResult = prime_multiply_mod(nResult, nBase, nModulus);
43  nExponent >>= 1;
44  nBase = prime_multiply_mod(nBase, nBase, nModulus);
45  }
46  return nResult;
47 }
48 
49 } // namespace details
50 
51 template<class I>
52 inline std::vector<I> find_prime_factors(I nValue)
53 {
54  static_assert(std::is_integral_v<I>, "Integral required");
55 
56  std::vector<I> factors;
57 
58  bool bValueNegative = false;
59  if constexpr (std::numeric_limits<I>::min() < 0)
60  {
61  if (nValue < 0)
62  {
63  bValueNegative = true;
64  nValue = -nValue;
65  }
66  }
67 
68  if (nValue > 1)
69  {
70  while (nValue % 2 == 0)
71  {
72  factors.push_back(2);
73  nValue /= 2;
74  }
75 
76  I i = 3u;
77  I nMaxFactor = static_cast<I>(std::sqrt(nValue));
78  while (i <= nMaxFactor)
79  {
80  while (nValue % i == 0)
81  {
82  factors.push_back(i);
83  nValue /= i;
84  nMaxFactor = static_cast<I>(std::sqrt(nValue));
85  }
86 
87  i += 2;
88  }
89 
90  if (nValue > 1)
91  factors.push_back(nValue);
92  }
93 
94  if constexpr (std::numeric_limits<I>::min() < 0)
95  if (!factors.empty() && bValueNegative)
96  factors[0] = -factors[0];
97 
98  return factors;
99 }
100 
101 template<class I>
102 inline std::vector<I> find_primes(I nMaxNumber)
103 {
104  static_assert(std::is_integral_v<I>, "Integral required");
105 
106  std::vector<bool> isComposite(static_cast<size_t>(nMaxNumber) + 1, false);
107 
108  constexpr size_t first_composite_power_of_two = 4;
109  for (size_t i = first_composite_power_of_two; i < static_cast<size_t>(nMaxNumber) + 1; i += 2)
110  {
111  isComposite[i] = true;
112  }
113 
114  I nNextPrime = 3;
115  I nStopAt = static_cast<I>(std::sqrt(nMaxNumber + 1));
116  while (nNextPrime <= nStopAt)
117  {
118  for (I i = nNextPrime * 2; i < nMaxNumber + 1; i += nNextPrime)
119  isComposite[static_cast<size_t>(i)] = true;
120 
121  nNextPrime += 2;
122 
123  while (nNextPrime <= nMaxNumber && isComposite[static_cast<size_t>(nNextPrime)])
124  {
125  nNextPrime += 2;
126  }
127  }
128 
129  std::vector<I> primes;
130  primes.reserve(static_cast<size_t>(nMaxNumber / 2)); // approximate size
131 
132  for (I i = 2; i < nMaxNumber + 1; ++i)
133  if (!isComposite[static_cast<size_t>(i)])
134  primes.push_back(i);
135 
136  primes.shrink_to_fit();
137  return primes;
138 }
139 
140 inline bool is_prime(size_t nValue)
141 {
142  return find_prime_factors(nValue).size() == 1;
143 }
144 
145 inline bool is_prime(size_t nValue, double fProbability)
146 {
147  if (fProbability < 0)
148  fProbability = -fProbability;
149 
150  if (fProbability >= 1 || std::fabs(fProbability) <= DBL_EPSILON)
151  return is_prime(nValue);
152 
153  constexpr double fLog2 = 0.30102999566; // std::log(2)
154 
155  const double fTests = std::ceil(std::log(1.0 / (1.0 - fProbability)) / fLog2);
156 
157  std::default_random_engine generator(static_cast<unsigned>(std::time(nullptr)));
158 
159  std::uniform_int_distribution<size_t> num_dist(2, nValue);
160 
161  for (unsigned i = 0; i < fTests; ++i)
162  {
163  const size_t nRandomNumber = num_dist(generator);
164  if (details::prime_power_mod(nRandomNumber, nValue - 1, nValue) != 1)
165  {
166  return false;
167  }
168  }
169 
170  return true;
171 }
172 
173 } // namespace qx
std::vector< I > find_primes(I nMaxNumber)
Find all primes between 2 and nMaxNumber.
Definition: prime.inl:102
bool is_prime(size_t nValue)
Is number prime.
Definition: prime.inl:140
std::vector< I > find_prime_factors(I nValue)
Find all prime factors.
Definition: prime.inl:52