aboutsummaryrefslogtreecommitdiff
path: root/06_storage/primes.c
blob: 4a17e8d8cde9d75a1859e4f7450761d0b80ca1c1 (plain)
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
93
94
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <pthread.h>

#include "primes.h"
#include "storage.h"

#define NTHREADS 16
#define INDEX(i) ((i) >> 3)
#define MASK(i) (unsigned char)(1 << ((i) % 8))

unsigned char primes_table[TABLESIZE];
struct interval { int low; int high; int count; };

void *pthread_routine(void *);
int primes_in_range(int, int, void (*)(const char *));
void set_nonprime(unsigned char *, int);
bool isprime(const unsigned char *, int);

int primes_in_range(int low, int high, void (*log)(const char *)) {
	static bool table_is_loaded = false;

	pthread_t threads[NTHREADS];
	struct interval args[NTHREADS];

	if (low < 0 || high < low)
		return 0;

	if (!table_is_loaded) {
		if (!read_table(primes_table)) {
			generate_primes(primes_table, log);
			if (!store_table(primes_table))
				log("Error storing table to indexed DB");
		}
		
		table_is_loaded = true;
	}

	int interval_size = (high-low)/NTHREADS + 1;
	for (int i = 0; i < NTHREADS; i++) {
		args[i].low = low + i*interval_size;
		args[i].high = args[i].low + interval_size;
		pthread_create(&threads[i], NULL, pthread_routine, &args[i]);
	}

	log("All threads have started, computing..."); 

	int result = 0;
	for (int i = 0; i < NTHREADS; i++) {
		pthread_join(threads[i], NULL);
		result += args[i].count;
	}

	return result;
}

void set_nonprime(unsigned char *table, int n) {
	table[INDEX(n)] &= ~MASK(n);
}

bool isprime(const unsigned char *table, int n) {
	return table[INDEX(n)] & MASK(n);
}

void generate_primes(unsigned char *table, void (*log)(const char *)) {
	memset(table, 0xFF, TABLESIZE);
	set_nonprime(table, 0);
	set_nonprime(table, 1);
	for (long long i = 0; i < MAX_PRIME; i++) {
		if (i % 100000000 == 0 && log != NULL) {
			char msg[200];
			sprintf(msg, 
			    "Could not read table of primes, generating it\n"
			    "Done %llu / %d", i, MAX_PRIME);
			log(msg);
		}
		if (!isprime(table, i))
			continue;
		for (long long int j = 2*i; j < MAX_PRIME; j += i)
			set_nonprime(table, j);
	}
}

void *pthread_routine(void *arg) {
	struct interval *interval = arg;

	interval->count = 0;
	for (int i = interval->low; i < interval->high; i++)
		if (isprime(primes_table, i))
			interval->count++;

	return NULL;
}

Generated with cgit - Back to sebastiano.tronto.net