Project Euler Solutions
primes.h
Go to the documentation of this file.
1 #ifndef PRIMES_H
2 #define PRIMES_H
3 
4 #include <stdint.h>
5 #include <string.h>
6 #include "macros.h"
7 
8 #include <stdlib.h>
9 #include <math.h>
10 
11 #include "iterator.h"
12 
13 #ifdef DOXYGEN
14 namespace c::include::primes {
15 #endif
16 
17 typedef struct prime_sieve prime_sieve;
18 
26 struct prime_counter {
27  size_t idx;
28  uintmax_t stop;
31 };
32 
37 struct prime_sieve {
39  uintmax_t prime_squared;
40  uintmax_t prime : (sizeof(uintmax_t) * 4);
41  // @cond SHOW_PADDING_VARS
42  uintmax_t _pad1 : (sizeof(uintmax_t) * 4);
43  bool _pad2 : 1;
44  // @endcond
45  size_t sieve_len : (sizeof(size_t) * 8 - 1);
46  uintmax_t *sieve;
47  uintmax_t candidate;
49 };
50 
51 static uintmax_t *prime_cache = NULL;
52 // note: If you let it, this will grow indefinitely. To not let it do so, #define PRIME_CACHE_SIZE_LIMIT
53 static uintmax_t prime_cache_max = 0;
54 static size_t prime_cache_size = 0;
55 static size_t prime_cache_idx = 0;
57 
65 
73  free_iterator(ps->source);
74  if (ps->sieve != NULL) {
75  free(ps->sieve);
76  }
77 }
78 
80  if (pc->ps != NULL) {
81  free_prime_sieve(pc->ps);
82  free(pc->ps);
83  }
84 }
85 
95  IterationHead(pc);
96  if (unlikely(pc->exhausted)) {
97  return 0;
98  }
99  if (!prime_cache_size) { // if not already done, initialize the prime cache
100  prime_cache = (uintmax_t *) malloc(sizeof(uintmax_t) * 4);
101  prime_cache[0] = 2;
102  prime_cache[1] = 3;
103  prime_cache[2] = 5;
104  prime_cache[3] = prime_cache_max = 7;
105  prime_cache_size = 4;
106  prime_cache_idx = 4;
107  }
108  if (pc->idx < prime_cache_idx) {
109  uintmax_t p = prime_cache[pc->idx++];
110  if ((pc->exhausted = (p >= pc->stop))) {
111  return 0;
112  }
113  return p;
114  }
115  if (pc->ps == NULL) {
116  // keep in mind that recursion on this block will never continue beyond 1 level unless the nested pc exceeds the cache size.
117  // pc makes a ps. ps makes a nested pc. the nested pc never makes a ps because it can feed entirely on the cache
118  // similar story if you start from ps. ps makes a pc. pc eventually makes a nested ps, which makes a nested pc
119  // the nested pc feeds entirely off the cache and never makes a doubly-tested pc.
120  prime_sieve to_copy = prime_sieve0();
121  pc->ps = (prime_sieve *) malloc(sizeof(prime_sieve));
122  memcpy(pc->ps, &to_copy, sizeof(prime_sieve));
123  while(next_p(pc->ps) < prime_cache[pc->idx - 1]) {}
124  }
125  const uintmax_t p = next_p(pc->ps);
126  if (pc->idx == prime_cache_idx) {
127  if (
128  prime_cache_size == prime_cache_idx
129  #ifdef PRIME_CACHE_SIZE_LIMIT
130  && prime_cache_size < PRIME_CACHE_SIZE_LIMIT
131  #endif
132  ) {
133  size_t new_size = prime_cache_size * 2;
134  #ifdef PRIME_CACHE_SIZE_LIMIT
135  if (new_size > PRIME_CACHE_SIZE_LIMIT) {
136  new_size = PRIME_CACHE_SIZE_LIMIT;
137  }
138  #endif
139  uintmax_t *tmp = (uintmax_t *) realloc(prime_cache, new_size * sizeof(uintmax_t));
140  if (tmp != NULL) {
141  prime_cache = tmp;
142  prime_cache_size = new_size;
143  prime_cache[prime_cache_idx++] = prime_cache_max = p;
144  }
145  }
146  else {
147  prime_cache[prime_cache_idx++] = p;
148  }
149  }
150  pc->idx++;
151  if ((pc->exhausted = (p >= pc->stop))) {
152  return 0;
153  }
154  return p;
155 }
156 
164 inline prime_counter prime_counter1(uintmax_t stop) {
168  ExtendInit(stop, stop)
169  );
170 }
171 
179  return prime_counter1(-1);
180 }
181 
191  // modified sieve of eratosthenes adapted to C from Python p0003
192  if (ps->candidate == 2) {
193  ps->candidate = 3;
194  return 2;
195  }
196  // if candidate in sieve
197  while (true) {
198  uintmax_t step;
199  bool candidate_in_sieve = false;
200  size_t candidate_index = -1;
201  for (size_t i = 0; i < ps->sieve_len * 2; i += 2) {
202  if (ps->sieve[i] == ps->candidate) {
203  step = ps->sieve[i + 1];
204  candidate_in_sieve = true;
205  candidate_index = i;
206  break;
207  }
208  }
209  if (!candidate_in_sieve) {
210  if (ps->candidate < ps->prime_squared) { // prime
211  uintmax_t ret = ps->candidate;
212  ps->candidate += 2;
213  return ret;
214  }
215  // == prime_squared
216  step = ps->prime * 2;
217  ps->prime = next(ps->source);
218  ps->prime_squared = ps->prime * ps->prime;
219  }
220  uintmax_t candidate = ps->candidate;
221  ps->candidate += 2;
222  do {
223  candidate += step;
224  candidate_in_sieve = false;
225  for (size_t i = 0; i < ps->sieve_len * 2; i += 2) {
226  if (ps->sieve[i] == candidate) {
227  candidate_in_sieve = true;
228  break;
229  }
230  }
231  } while (candidate_in_sieve);
232  if (candidate_index != -1) {
233  ps->sieve[candidate_index] = candidate;
234  } else {
235  ps->sieve_len++;
236  ps->sieve = (uintmax_t *) realloc(ps->sieve, ps->sieve_len * 2 * sizeof(uintmax_t));
237  ps->sieve[(ps->sieve_len - 1) * 2] = candidate;
238  ps->sieve[ps->sieve_len * 2 - 1] = step;
239  }
240  }
241 }
242 
250  advance_prime_sieve,
251  AddDestructor(free_prime_sieve),
252  ExtendInit(source, prime_counter0()),
253  ExtendInit(prime, 3),
254  ExtendInit(prime_squared, 9),
255  ExtendInit(candidate, 2)
256  );
257  next(ret.source);
258  next(ret.source);
259  return ret;
260 }
261 
262 
269  uintmax_t target;
270  uintmax_t current;
273 };
274 
283  free_iterator(pfc->pc);
284 }
285 
295  while (pfc->target != 0 && pfc->target != 1 && !pfc->pc.exhausted) {
296  if (pfc->target % pfc->current == 0) {
297  pfc->target /= pfc->current;
298  pfc->exhausted = (pfc->target == 1);
299  return pfc->current;
300  }
301  pfc->current = next(pfc->pc);
302  }
303  pfc->exhausted = true;
304  return -1;
305 }
306 
316  advance_prime_factor_counter,
318  ExtendInit(pc, prime_counter0()),
319  ExtendInit(current, 2),
320  ExtendInit(target, n)
321  );
322  next(ret.pc);
323  return ret;
324 }
325 
333 uintmax_t is_composite(uintmax_t n) {
334  if (!n || n == 1) {
335  return 0;
336  }
338  uintmax_t ret = next(iter);
339  free_iterator(iter);
340  if (ret == n) {
341  return 0;
342  }
343  return ret;
344 }
345 
353 bool is_prime(uintmax_t n);
354 inline bool is_prime(uintmax_t n) {
355  return n && n != 1 && !is_composite(n);
356 }
357 
358 #ifdef DOXYGEN
359 };
360 #endif
361 
362 #endif
prime_counter prime_counter0()
The simplest constructor for the prime number generator.
Definition: primes.h:178
static uintmax_t prime_cache_max
Definition: primes.h:53
uintmax_t advance_prime_factor_counter(prime_factor_counter *pfc)
The function to advance a prime factor iterator.
Definition: primes.h:294
#define IteratorInitHead(advance,...)
The base macro for all iterator initialization functions in this project.
Definition: iterator.h:111
#define IteratorTail(return_type, struct_type)
The base definition macro for all iterators in this project.
Definition: iterator.h:46
size_t sieve_len
The length of the sieve state (divided by 2)
Definition: primes.h:45
static size_t prime_cache_idx
Definition: primes.h:55
size_t idx
The current position of the counter.
Definition: primes.h:27
uintmax_t * sieve
The sieve state used to generate new primes stored as pairs of [value, step].
Definition: primes.h:46
static size_t prime_cache_size
Definition: primes.h:54
def prime_factors
Definition: p0003.py:98
Definition: primes.h:37
bool exhausted
An indicator that the iterator has stopped.
Definition: iterator.h:231
#define ExtendInit(name, value)
The extension macro for initializing more complicated Iterators.
Definition: iterator.h:168
prime_counter source
The source of new reference prime numbers.
Definition: primes.h:38
#define free_iterator(it)
The generic destructor for iterators.
Definition: iterator.h:207
void free_prime_counter(prime_counter *pc)
The destructor for the prime number counter.
Definition: primes.h:79
uintmax_t is_composite(uintmax_t n)
Tells you if a number is composite, and if so, its smallest prime factor.
Definition: primes.h:333
#define AddDestructor(func)
The extension macro for initializing Iterators with a destructor.
Definition: iterator.h:145
A cached prime number generator.
Definition: primes.h:26
#define next(state)
The macro to advance generic iterators.
Definition: iterator.h:180
prime_counter pc
The prime number generator being used to test.
Definition: primes.h:271
uintmax_t stop
The point where the counter is exhausted.
Definition: primes.h:28
void free_prime_factor_counter(prime_factor_counter *pfc)
Definition: primes.h:282
prime_sieve * ps
A (currently unused) source for new prime numbers.
Definition: primes.h:29
uintmax_t prime_squared
The reference prime squared.
Definition: primes.h:39
uintmax_t candidate
The current candidate prime number.
Definition: primes.h:47
prime_sieve prime_sieve0()
#define next_p(state)
The macro to advance generic iterator pointers.
Definition: iterator.h:192
uintmax_t current
The prime number most recently tested.
Definition: primes.h:270
#define IterationHead(it)
The base macro for all iteration functions in this project.
Definition: iterator.h:74
bool is_prime(uintmax_t n)
Tells you if a number is prime.
Definition: primes.h:354
void free_prime_sieve(prime_sieve *ps)
The destructor for the prime number sieve.
Definition: primes.h:72
prime_factor_counter prime_factors(uintmax_t n)
The base constructor for the prime factors iterator.
Definition: primes.h:314
prime_sieve prime_sieve0()
The constructor for the prime number sieve.
Definition: primes.h:248
uintmax_t prime
The current reference prime.
Definition: primes.h:40
uintmax_t advance_prime_counter(prime_counter *pc)
The function to advance a prime number generator.
Definition: primes.h:94
uintmax_t target
The current target for prime factorization.
Definition: primes.h:269
#define unlikely(x)
Indicates to the compiler (if supported) that this branch is unlikely to occur and it should arrange ...
Definition: math.h:152
An implementation of Python-like iterators and generators using macros to maintain static typing...
prime_counter prime_counter1(uintmax_t stop)
The base constructor for the prime number generator.
Definition: primes.h:164
Definition: primes.h:14
uintmax_t advance_prime_sieve(prime_sieve *ps)
The function to advance a prime sieve iterator.
Definition: primes.h:190
static uintmax_t * prime_cache
Definition: primes.h:51