primes.h
View source code here on GitHub!
Includes
"math.h" (if compiled on PCC)
"macros.h" (implicitly, via iterator.h)
<stdbool.h>
(implicitly, via iterator.h)<stdlib.h>
(if not compiled on PCC)<math.h>
(if not compiled on PCC)
-
type prime_counter
Implements the
Iterator
API and yields successive prime numbers.-
uintmax_t (*iterator_function)(prime_counter *pc)
The function to advance the iterator and return the next element.
-
bool exhausted : 1
An indicator that tells you if the iterator is exhausted.
-
bool started : 1
An indicator that tells you if the interator has moved at all.
-
bool phase : 1
An indicator that flips every time the iterator moves
-
size_t idx
The current position of the counter.
-
uintmax_t stop
The point where the counter is exhausted.
-
prime_sieve *ps
-
prime_counter prime_counter1(uintmax_t stop)
-
prime_counter prime_counter0()
-
void free_prime_counter(prime_counter pc)
-
uintmax_t (*iterator_function)(prime_counter *pc)
-
type prime_sieve
An
Iterator
that implements a modified sieve of eratosthenes-
uintmax_t (*iterator_function)(prime_sieve *ps)
The function to advance the iterator and return the next element.
-
bool exhausted : 1
An indicator that tells you if the iterator is exhausted.
-
bool started : 1
An indicator that tells you if the iterator has moved at all.
-
bool phase : 1
An indicator that flips every time the iterator moves.
-
uintmax_t *sieve
The sieve state used to generate new primes.
-
size_t sieve_len
The length of the sieve state (divided by 2).
-
uintmax_t prime
The current reference prime.
-
uintmax_t prime_squared
The reference prime squared.
-
uintmax_t candidate
The current candidate prime number.
-
prime_counter source
The source of new reference prime numbers.
-
prime_sieve prime_sieve0()
-
void free_prime_sieve(prime_sieve ps)
-
uintmax_t (*iterator_function)(prime_sieve *ps)
-
type prime_factor_counter
Implements the
Iterator
API and yields successive prime factors.-
uintmax_t (*iterator_function)(prime_factor_counter *pfc)
The function to advance the iterator and return the next element.
-
bool exhausted : 1
An indicator that tells you if the iterator is exhausted.
-
bool started : 1
An indicator that tells you if the interator has moved at all.
-
bool phase : 1
An indicator that flips every time the iterator moves.
-
uintmax_t target
The number you are trying to factorize.
-
uintmax_t current
The current candidate prime factor.
-
prime_counter pc
The source of new prime numbers
-
uintmax_t (*iterator_function)(prime_factor_counter *pfc)
-
prime_factor_counter prime_factors(uintmax_t n)
-
free_prime_factor_counter(pfc)
-
uintmax_t is_composite(uintmax_t n)
Tells you if a number is composite, and if so, its smallest prime factor.
-
bool is_prime(uintmax_t n)
Tests if a number is prime.
1#pragma once
2
3#include <stdint.h>
4#include <inttypes.h>
5#include "macros.h"
6
7#if !PCC_COMPILER
8 #include <stdlib.h>
9 #include <math.h>
10#else
11 #include "math.h"
12#endif
13
14#include "iterator.h"
15
16typedef struct prime_sieve prime_sieve;
17typedef struct prime_counter prime_counter;
18struct prime_counter {
19 /**
20 * The reference struct for all iterators in this project
21 * @iterator_function: The function to advance the iterator and return the next element
22 * @exhausted: An indicator that tells you if the iterator is exhausted
23 * @started: An indicator that tells you if the interator has moved at all
24 * @phase: An indicator that flips every time the iterator moves
25 * @idx: The current position of the counter
26 * @stop: The point where the counter is exhausted
27 *
28 * See IteratorHead
29 */
30 IteratorHead(uintmax_t, prime_counter);
31 size_t idx;
32 uintmax_t stop;
33 prime_sieve *ps;
34};
35
36static uintmax_t *prime_cache;
37// note: If you let it, this will grow indefinitely. To not let it do so, #define PRIME_CACHE_SIZE_LIMIT
38static uintmax_t prime_cache_max = 0;
39static size_t prime_cache_size = 0;
40static size_t prime_cache_idx = 0;
41prime_sieve prime_sieve0();
42
43uintmax_t advance_prime_counter(prime_counter *pc) {
44 /**
45 * The function to advance a prime number generator
46 * @pc the counter you want to advance
47 *
48 * Returns the next number in the iteration
49 */
50 IterationHead(pc);
51 if (!prime_cache_size) { // if not already done, initialize the prime cache
52 prime_cache = (uintmax_t *) malloc(sizeof(uintmax_t) * 4);
53 prime_cache[0] = 2;
54 prime_cache[1] = 3;
55 prime_cache[2] = 5;
56 prime_cache[3] = prime_cache_max = 7;
57 prime_cache_size = 4;
58 prime_cache_idx = 4;
59 }
60 if (pc->idx < prime_cache_idx) {
61 uintmax_t p = prime_cache[pc->idx++];
62 if ((pc->exhausted = (p >= pc->stop)))
63 return 0;
64 return p;
65 }
66 for (uintmax_t p = prime_cache[pc->idx - 1] + 2; p < pc->stop; p += 2) {
67 bool broken = false;
68 for (size_t idx = 1; idx < prime_cache_idx; idx++)
69 if (p % prime_cache[idx] == 0) { // is not prime
70 broken = true;
71 break;
72 }
73 if (!broken) { // primeness not determined, exceeded cache
74 uintmax_t root_p = ceil(sqrt(p));
75 for (uintmax_t c = prime_cache_max; c <= root_p; c += 2) {
76 if (p % c == 0) { // is not prime
77 broken = true;
78 break;
79 }
80 }
81 }
82 if (!broken) { // is prime
83 if (pc->idx == prime_cache_idx) {
84#ifdef PRIME_CACHE_SIZE_LIMIT
85 if (prime_cache_size == prime_cache_idx && prime_cache_size < PRIME_CACHE_SIZE_LIMIT)
86#else
87 if (prime_cache_size == prime_cache_idx)
88#endif
89 {
90 size_t new_size = prime_cache_size * 2;
91#ifdef PRIME_CACHE_SIZE_LIMIT
92 if (new_size > PRIME_CACHE_SIZE_LIMIT)
93 new_size = PRIME_CACHE_SIZE_LIMIT;
94#endif
95 void *tmp = realloc(prime_cache, new_size * sizeof(uintmax_t));
96 if (tmp != NULL) {
97 prime_cache = (uintmax_t *) tmp;
98 prime_cache_size = new_size;
99 prime_cache[prime_cache_idx++] = prime_cache_max = p;
100 }
101 }
102 else
103 prime_cache[prime_cache_idx++] = p;
104 }
105 pc->idx++;
106 if ((pc->exhausted = (p >= pc->stop)))
107 return 0;
108 return p;
109 }
110 }
111 pc->exhausted = true; // shouldn't get here, but just in case
112 return 0;
113}
114
115prime_counter prime_counter1(uintmax_t stop) {
116 /**
117 * The base constructor for the prime number generator
118 * @stop: The point where the counter is exhausted
119 *
120 * See prime_counter
121 */
122 prime_counter ret;
123 IteratorInitHead(ret, advance_prime_counter);
124 ret.idx = 0;
125 ret.stop = stop;
126 ret.ps = NULL;
127 return ret;
128}
129
130prime_counter prime_counter0();
131inline prime_counter prime_counter0() {
132 /**
133 * The simplest constructor for the prime number generator
134 *
135 * See prime_counter
136 */
137 return prime_counter1(-1);
138}
139
140struct prime_sieve {
141 /**
142 * The iterator that implements a modified sieve of eratosthenes
143 * @iterator_function: The function to advance the iterator and return the next element
144 * @exhausted: An indicator that tells you if the iterator is exhausted
145 * @started: An indicator that tells you if the iterator has moved at all
146 * @phase: An indicator that flips every time the iterator moves
147 * @sieve: The sieve state used to generate new primes
148 * @sieve_len: The length of the sieve state (divided by 2)
149 * @prime: The current reference prime
150 * @prime_squared: The reference prime squared
151 * @candidate: The current candidate prime number
152 * @source: The source of new reference prime numbers
153 *
154 * See IteratorHead
155 */
156 IteratorHead(uintmax_t, prime_sieve);
157 uintmax_t *sieve;
158 size_t sieve_len;
159 uintmax_t prime;
160 uintmax_t prime_squared;
161 uintmax_t candidate;
162 prime_counter source;
163};
164
165uintmax_t advance_prime_sieve(prime_sieve *ps) {
166 /**
167 * The function to advance a prime sieve iterator
168 * @ps the sieve you want to advance
169 *
170 * Returns the next prime number in the iteration
171 */
172 // modified sieve of eratosthenes adapted to C from Python p0003
173 if (ps->candidate == 2) {
174 ps->candidate = 3;
175 return 2;
176 }
177 // if candidate in sieve
178 while (true) {
179 uintmax_t step;
180 bool candidate_in_sieve = false;
181 size_t candidate_index = -1;
182 for (size_t i = 0; i < ps->sieve_len * 2; i += 2)
183 if (ps->sieve[i] == ps->candidate) {
184 step = ps->sieve[i + 1];
185 candidate_in_sieve = true;
186 candidate_index = i;
187 break;
188 }
189 if (!candidate_in_sieve) {
190 if (ps->candidate < ps->prime_squared) { // prime
191 uintmax_t ret = ps->candidate;
192 ps->candidate += 2;
193 return ret;
194 }
195 // == prime_squared
196 step = ps->prime * 2;
197 ps->prime = next(ps->source);
198 ps->prime_squared = ps->prime * ps->prime;
199 }
200 uintmax_t candidate = ps->candidate;
201 ps->candidate += 2;
202 do {
203 candidate += step;
204 candidate_in_sieve = false;
205 for (size_t i = 0; i < ps->sieve_len * 2; i += 2)
206 if (ps->sieve[i] == candidate) {
207 candidate_in_sieve = true;
208 break;
209 }
210 } while (candidate_in_sieve);
211 if (candidate_index != -1)
212 ps->sieve[candidate_index] = candidate;
213 else {
214 ps->sieve_len++;
215 ps->sieve = (uintmax_t *) realloc(ps->sieve, ps->sieve_len * 2 * sizeof(uintmax_t));
216 ps->sieve[(ps->sieve_len - 1) * 2] = candidate;
217 ps->sieve[ps->sieve_len * 2 - 1] = step;
218 }
219 }
220}
221
222prime_sieve prime_sieve0() {
223 /**
224 * The constructor for the prime number sieve
225 *
226 * See prime_sieve
227 */
228 prime_sieve ret;
229 IteratorInitHead(ret, advance_prime_sieve);
230 ret.sieve = NULL;
231 ret.sieve_len = 0;
232 ret.prime = 3;
233 ret.prime_squared = 9;
234 ret.candidate = 2;
235 ret.source = prime_counter0();
236 next(ret.source);
237 next(ret.source);
238 return ret;
239}
240
241void free_prime_counter(prime_counter pc);
242void free_prime_sieve(prime_sieve ps) {
243 free_prime_counter(ps.source);
244 if (ps.sieve != NULL)
245 free(ps.sieve);
246}
247
248void free_prime_counter(prime_counter pc) {
249 if (pc.ps != NULL) {
250 free_prime_sieve(*pc.ps);
251 free(pc.ps);
252 }
253}
254
255typedef struct prime_factor_counter prime_factor_counter;
256struct prime_factor_counter {
257 /**
258 * The iterator that allows you to prime factorize a number
259 * @iterator_function: The function to advance the iterator and return the next element
260 * @exhausted: An indicator that tells you if the iterator is exhausted
261 * @started: An indicator that tells you if the interator has moved at all
262 * @phase: An indicator that flips every time the iterator moves
263 * @target: The current target for prime factorization (note: this will change after construction)
264 * @current: The prime number most recently tested
265 * @pc: The prime number generator being used to test
266 *
267 * See IteratorHead
268 */
269 IteratorHead(uintmax_t, prime_factor_counter);
270 uintmax_t target;
271 uintmax_t current;
272 prime_counter pc;
273};
274
275uintmax_t advance_prime_factor_counter(prime_factor_counter *pfc) {
276 /**
277 * The function to advance a prime factor iterator
278 * @i the counter you want to advance
279 *
280 * Returns the next number in the iteration
281 */
282 while (pfc->target != 0 && pfc->target != 1 && !pfc->pc.exhausted) {
283 if (pfc->target % pfc->current == 0) {
284 pfc->target /= pfc->current;
285 pfc->exhausted = (pfc->target == 1);
286 return pfc->current;
287 }
288 pfc->current = next(pfc->pc);
289 }
290 pfc->exhausted = true;
291 return -1;
292}
293
294prime_factor_counter prime_factors(uintmax_t n) {
295 /**
296 * The base constructor for the prime factors iterator
297 * @n: The non-zero number you wish to factor
298 *
299 * WARNING: if you put in 0, behaviour is undefined
300 *
301 * See prime_factor_counter
302 */
303 prime_factor_counter ret;
304 IteratorInitHead(ret, advance_prime_factor_counter);
305 ret.current = 2;
306 ret.target = n;
307 ret.pc = prime_counter0();
308 next(ret.pc);
309 return ret;
310}
311
312#define free_prime_factor_counter(pfc) free_prime_counter(pfc.pc)
313
314uintmax_t is_composite(uintmax_t n) {
315 /**
316 * Tells you if a number is composite, and if so, its smallest prime factor
317 * @n: The number you wish to test
318 *
319 * See prime_factor_counter
320 */
321 if (!n || n == 1)
322 return 0;
323 prime_factor_counter iter = prime_factors(n);
324 uintmax_t ret = next(iter);
325 if (ret == n)
326 return 0;
327 return ret;
328}
329
330bool is_prime(uintmax_t n);
331inline bool is_prime(uintmax_t n) {
332 /**
333 * Tells you if a number is prime
334 * @n: The number you wish to test
335 *
336 * See prime_factor_counter
337 */
338 return n && n != 1 && !is_composite(n);
339}