primes.h

View source code here on GitHub!

Includes

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)
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)
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

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}

Tags: prime-number, divisibility, factorization, c-iterator