new file: primeCalc/.gitignore
new file: primeCalc/Makefile new file: primeCalc/README.md new file: primeCalc/src/prime_ex.c new file: primeCalc/src/sieve.c new file: primeCalc/src/sieve.hmain
parent
1843315b51
commit
b1cdfa01d9
|
@ -0,0 +1,3 @@
|
|||
prime.txt
|
||||
fastOut
|
||||
debugOut
|
|
@ -0,0 +1,18 @@
|
|||
CFLAGSD=-g -ggdb -Wall -Wextra -Werror
|
||||
CFLAGSF=-Wall -Wextra -Ofast -march=native -mtune=native -funroll-all-loops
|
||||
FILES=src/sieve.c src/sieve.h src/prime_ex.c
|
||||
|
||||
all: fast
|
||||
|
||||
debug: $(FILES)
|
||||
gcc $(CFLAGSD) $(FILES) -o debugOut
|
||||
|
||||
fast: $(FILES)
|
||||
gcc $(CFLAGSF) $(FILES) -o fastOut
|
||||
|
||||
clean:
|
||||
rm -rf *.o debugOut fastOut prime.txt
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
# Prime Sieve
|
||||
|
||||
Prime sieve using bitfields
|
||||
|
||||
'make' for fast benchmark output
|
||||
|
||||
'make debug' for debugOut
|
||||
|
||||
If program does not finish in appropriate time adjust n_per_clock in src/sieve.c
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#include "sieve.h"
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
FILE *ptr_file;
|
||||
ptr_file = fopen("prime.txt", "w");
|
||||
|
||||
clock_t t_0 = clock();
|
||||
//// prime algorithm START ////
|
||||
sieve(argc, argv, ptr_file);
|
||||
|
||||
//// prime algorithm END ////
|
||||
clock_t t_E = clock();
|
||||
|
||||
fclose(ptr_file);
|
||||
|
||||
float t_delta = (float)(t_E - t_0) / CLOCKS_PER_SEC;
|
||||
printf("\nTime in Seconds: %.3f\n", t_delta);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/*Author: Simon Schurti
|
||||
*License: MIT
|
||||
*
|
||||
*
|
||||
* Prime sieve using bitfields & masks
|
||||
*/
|
||||
|
||||
#include "sieve.h"
|
||||
|
||||
// primes up to n per clock
|
||||
// may need adjusting on different platform to finish in appropiate time
|
||||
const WORD n_per_clock = 130;
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
WORD upperLimit = 4e9;
|
||||
// WORD upperLimit = 542;
|
||||
|
||||
// fast square root approximation function for unsigned ints
|
||||
// uses Herons Method
|
||||
// https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Heron's_method
|
||||
WORD root(WORD n) {
|
||||
|
||||
WORD x = 0x1 << (MSB(n) - 2); // initial estimate 2 orders smaller than n
|
||||
WORD prev = 0;
|
||||
while (x != prev) {
|
||||
prev = x;
|
||||
x = (x + (n / x)) / 2;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
// find next set bit > prime
|
||||
// this will be next prime as all numbers up to next prime should be eliminated
|
||||
WORD findNextPrime(WORD *sieve, WORD prime) {
|
||||
WORD next = prime + 2;
|
||||
/*printf("word: %lb\n", sieve[WordIdx(next)]);*/
|
||||
while (IsSet(sieve[WordIdx(next)], next) == 0) {
|
||||
// printf("%lu is not prime\n", next);
|
||||
next += 2;
|
||||
if (next >= upperLimit)
|
||||
return 0;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
int sieve(int argc, char **argv, FILE *fp) {
|
||||
int targetTime = 15;
|
||||
if (argc > 1) {
|
||||
targetTime = atoi(argv[1]);
|
||||
}
|
||||
upperLimit = (targetTime * CLOCKS_PER_SEC) * n_per_clock;
|
||||
|
||||
// upperLimit = 1e6;
|
||||
|
||||
printf("calculating0 up to : %lu\n", upperLimit);
|
||||
|
||||
// 1 bit per prime candidate / 2 beacause all even can be ignored
|
||||
WORD buffSize = upperLimit / 2 / BitsPerWord;
|
||||
|
||||
// main sieve buffer
|
||||
WORD *sieve = (WORD *)calloc(buffSize, BitsPerWord);
|
||||
if (sieve == NULL) {
|
||||
perror("calloc: ");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// initialize all as prime
|
||||
|
||||
WORD i = buffSize + 1;
|
||||
while (i--) {
|
||||
sieve[i] |= ones;
|
||||
}
|
||||
|
||||
WORD idx;
|
||||
WORD nextPrime = 3; // 2 can be assumed 3=2+1
|
||||
WORD MaxPrime = nextPrime;
|
||||
WORD primesFound = 1; // 2 is prime
|
||||
|
||||
//// findNextPrime returns 0 if none found in limit
|
||||
while (nextPrime > 0 && nextPrime < upperLimit) {
|
||||
primesFound++;
|
||||
WORD maxFactor = upperLimit / nextPrime;
|
||||
for (WORD factor = nextPrime; factor <= maxFactor; factor += 2) {
|
||||
idx = factor * nextPrime;
|
||||
if (idx >= upperLimit)
|
||||
break;
|
||||
/*printf("eliminating %lu because %lu * %lu = %lu\n", idx, factor,*/
|
||||
/* nextPrime, factor * nextPrime);*/
|
||||
// printf("with mask: %llb\n", BitIdxMask(idx));
|
||||
|
||||
sieve[WordIdx(idx)] &=
|
||||
sieve[WordIdx(idx)] ^
|
||||
(BitIdxMask(idx)); // set multiple of next prime to 0
|
||||
|
||||
// printf("new bu[%lu]: %lb\n", WordIdx(idx), sieve[WordIdx(idx)]);
|
||||
}
|
||||
// printf("-----> %lu %llb\n", nextPrime, BitIdxMask(nextPrime));
|
||||
MaxPrime = nextPrime;
|
||||
fprintf(fp, "%lu\n", nextPrime); // write prime number to textfile
|
||||
nextPrime = findNextPrime(sieve, nextPrime);
|
||||
}
|
||||
printf("found %lu primes\nmax prime: %lu\n", primesFound, MaxPrime);
|
||||
free(sieve);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef SIEVE
|
||||
#define SIEVE
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define WORD uint64_t
|
||||
#define BYTE uint8_t
|
||||
#define BitsPerWord 64
|
||||
#define ones 0xFFFFFFFFFFFFFFFFuLL
|
||||
|
||||
// find index of word that contains nth bit in total buffer /2 because no evens
|
||||
#define WordIdx(n) (((n) / 2) / BitsPerWord)
|
||||
// bit offset in word
|
||||
#define BitIdx(n) ((((n) / 2) % BitsPerWord))
|
||||
|
||||
// mask(3) = 0b10
|
||||
#define BitIdxMask(n) 0x1ull << (BitIdx(n))
|
||||
|
||||
#define IsSet(w, b) (w & BitIdxMask(b))
|
||||
|
||||
// find most significant bit
|
||||
//__builtin_clz should work with gcc on all platforms
|
||||
#define MSB(n) (BitsPerWord - 1 - __builtin_clz(n))
|
||||
int sieve(int argc, char **argv, FILE *fp);
|
||||
|
||||
#endif // !SIEVE
|
Loading…
Reference in New Issue