diff --git a/README.md b/README.md index 8f12710..37048ce 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,10 @@ A fast prime number generator in C Language ### Help -> ```fast_primes_ll -h``` +```fast_primes_ll -h``` ### Install -> ```make install``` +```make install``` ### Usage -> ```fast_primes_ll -isprime 331 # for example``` +```fast_primes_ll -isprime 331 # for example``` diff --git a/fast_primes_ll.c b/fast_primes_ll.c index 515377a..4cfdf3c 100644 --- a/fast_primes_ll.c +++ b/fast_primes_ll.c @@ -17,55 +17,15 @@ * If not, see . **/ -/** -* Headers -**/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - +#include "fast_primes_ll.h" #define NAME "fast_primes_ll" -#define VERSION "1.0" +#define VERSION "1.1" #define AUTHOR "Toni Helminen" -#define BITBOARD unsigned long long -#define MAX_TOKENS 128 - -/** -* Macros -**/ - -#define INT(a) ((int) (a)) -#define DOUBLE(f) ((double) (f)) -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#define ULL(a) ((BITBOARD) (a)) -#define FCP_ASSERT(test) if ( ! (test)) {P("fast_primes_ll Error: Line: %i", __LINE__); exit(0);} - -static bool Token_ok(); -static void Token_reset(); -static void Token_add(const char *s); -static void P(const char *format, ...); -static void Print_primes(const int usize); -static bool User_is_prime(const int prime); -static void Add_prime(const int prime); -static int Next_prime(); -static void Init_primes(); -static void Bench(); -static void Insert_primes(const int usize); +#define HASH_SIZE 64 /* MB / Starting size */ typedef struct { - BITBOARD *primes; + int *primes; BITBOARD size; int primes_n; int count; @@ -73,7 +33,7 @@ typedef struct { int key; } HASHTABLE_T; -static char TOKENS[MAX_TOKENS][256] = {{0}}; // too plenty? +static char TOKENS[MAX_TOKENS][256] = {{0}}; static int TOKENS_N = 0; static int TOKENS_I = 0; static HASHTABLE_T HASH = {0}; @@ -93,7 +53,6 @@ static bool Equal_strings(const char *a, const char *b) return strcmp(a, b) ? 0 : 1; } - static BITBOARD Now() { static struct timeval t; @@ -152,7 +111,7 @@ static bool Token_is(const char *s) static void Token_expect(const char *s) { if ( ! Token_is(s)) { - P("Error: Unexpected Token: '%s'", Token_current()); + P("{ Error: Unexpected Token: '%s' }", Token_current()); exit(0); } Token_pop(); @@ -208,7 +167,7 @@ static void Hashtable_set_size(const int usize /* MB */) HASH.key <<= 1; HASH.key >>= 1; HASH.key -= 1; // 1000b = 8d / - 1d / 0111b = 7d - HASH.primes = (BITBOARD*) calloc(HASH.count, sizeof(BITBOARD)); // <- Cast for g++ + HASH.primes = (int*) calloc(HASH.count, sizeof(int)); // <- Cast for g++ FCP_ASSERT(HASH.primes != NULL) // Make sure there is enough space Init_primes(); } @@ -216,16 +175,16 @@ static void Hashtable_set_size(const int usize /* MB */) static void Hashtable_make_bigger() { HASH.count = 2 * HASH.count; - HASH.primes = (BITBOARD*) realloc(&HASH, HASH.count * sizeof(BITBOARD)); // <- Cast for g++ + HASH.primes = (int*) realloc(&HASH, HASH.count * sizeof(int)); // <- Cast for g++ } static void System() { P("{ # Hash"); P(" HASH.primes_n = %i,", HASH.primes_n); - P(" HASH.size = %i MB,", (HASH.count * (sizeof(BITBOARD))) / (1024 * 1024)); - P(" HASH.count = %i,", HASH.count); - P(" HASH.key = %i}", HASH.key); + P(" HASH.size = %i # MB,", (HASH.count * (sizeof(BITBOARD))) / (1024 * 1024)); + P(" HASH.count = %i,", HASH.count); + P(" HASH.key = %i", HASH.key); P("}"); } @@ -236,7 +195,6 @@ static void Print_version() P(" version = %s,", VERSION); P(" author = %s,", AUTHOR); P(" description = fast_primes_ll, A fast prime number generator in C Language"); - P("}"); } @@ -249,17 +207,18 @@ static void Print_help() P(" fast_primes_ll -isprime 882 # is it a prime?"); P("}"); P(""); - P("{ # fast_primes_ll commands"); + P("{ # Commands"); P(" -h(elp) = This help,"); P(" -v(ersion) = Version,"); P(" -bench = Benchmark fast_primes_ll,"); P(" -system = System info,"); - P(" -isprime [NUM] = Check if whether this number is a prime,"); + P(" -isprime [NUM] = Check if whether N is a prime,"); + P(" -nthprime [NUM] = Get N:th prime,"); P(" -list [NUM] = Print all primes up to N"); P("}"); P(""); - P("{ # Full source code, please see"); - P(" "); + P("{ # Full source code, please see:"); + P(" "); P("}"); exit(0); } @@ -273,6 +232,27 @@ static void Command_isprime() P("{ No, %i is not a prime number. }", n); } +static int Nth_prime(const int prime_n) +{ + int n = Max(0, prime_n); + if (n < HASH.primes_n) + return HASH.primes[n]; + while (1) { + Add_prime(Next_prime()); + if (HASH.primes_n == n) + return Last_prime(); + } +} + +static void Command_nthprime() +{ + int n = Token_next_int(); + P("{ # Results nthprime"); + P(" N = %i,", n); + P(" nthprime = %i", Nth_prime(n - 1)); + P("}"); +} + static void Command_list() { int n = Max(10, Token_next_int()); @@ -282,9 +262,8 @@ static void Command_list() static void Add_prime(const int prime) { - if (HASH.primes_n >= HASH.count) { + if (HASH.primes_n >= HASH.count) Hashtable_make_bigger(); - } HASH.primes[HASH.primes_n] = prime; HASH.primes_n++; } @@ -326,14 +305,12 @@ static int Next_prime() { int candidate = Last_prime() + 1; while (1) { - if (Is_prime(candidate)) { + if (Is_prime(candidate)) return candidate; - } else { + else candidate++; - } } FCP_ASSERT(0) - return 0; } static void Insert_primes(const int usize) @@ -354,17 +331,23 @@ static void Init_primes() static void Bench() { int i; - P("> Benching ..."); + P("> Benching ...\n"); BITBOARD diff; BITBOARD start = Now(); HASH.primes_n = 0; // Just for benching Add_prime(2); Add_prime(3); - for (i = 0; i < 30000; i++) + for (i = 0; i < 100000; i++) { + if ((i + 1) % 10000 == 0) + P("{ done = %i%% }", (i + 1) / 1000); Add_prime(Next_prime()); + } diff = Now() - start; - P("{ # Results"); - P(" time = %.3fs,\n primes_per_second = %llu\n}", 0.001f * DOUBLE(diff), Nps(HASH.primes_n, diff)); + P(""); + P("{ # Benchmarks"); + P(" time = %.3fs,", 0.001f * DOUBLE(diff)); + P(" primes_per_second = %llu", Nps(HASH.primes_n, diff)); + P("}"); } static void Print_primes(const int usize) @@ -393,6 +376,8 @@ static void FCP_commands() System(); else if (Token_next("list")) Command_list(); + else if (Token_next("nthprime")) + Command_nthprime(); Token_expect(";"); } if (TOKENS_N < 2) @@ -403,7 +388,6 @@ static void Init_tokens(int argc, char **argv) { int i; Token_reset(); - // "-koth -perft 5" -> "; koth ; perft 5 ;" for (i = 1 /* skip ./fast_primes_ll */; i < argc; i++) { if (argv[i][0] == '-' && strlen(argv[i]) > 1) { Token_add(";"); @@ -413,15 +397,28 @@ static void Init_tokens(int argc, char **argv) } } Token_add(";"); - // Debug_tokens(); +} + +static void Ok() +{ + FCP_ASSERT(User_is_prime(37)); + FCP_ASSERT(User_is_prime(53)); + FCP_ASSERT(Nth_prime(17) == 59); + FCP_ASSERT(Nth_prime(34) == 139); +} + +static void Go() +{ + Hashtable_set_size(HASH_SIZE); + Init_primes(); + Ok(); + FCP_commands(); } int main(int argc, char **argv) { atexit(Free_memory); // No memory leaks Init_tokens(argc, argv); - Hashtable_set_size(64); // 64MB | Starting size - Init_primes(); - FCP_commands(); + Go(); return EXIT_SUCCESS; -} +} \ No newline at end of file diff --git a/fast_primes_ll.h b/fast_primes_ll.h new file mode 100644 index 0000000..41b344d --- /dev/null +++ b/fast_primes_ll.h @@ -0,0 +1,63 @@ +#ifndef FAST_PRIMES_LL_H +#define FAST_PRIMES_LL_H + +#include +#include +#include +#include +#include +#include + +#define BITBOARD unsigned long long +#define MAX_TOKENS 128 + +#define INT(a) ((int) (a)) +#define DOUBLE(f) ((double) (f)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define ULL(a) ((BITBOARD) (a)) +#define FCP_ASSERT(test) if ( ! (test)) {P("fast_primes_ll Error: Line: %i", __LINE__); exit(0);} + +static inline /* <- make me faster! */ int Max(const int a, const int b); +static inline int Min(const int a, const int b); +static bool Equal_strings(const char *a, const char *b); +static BITBOARD Now(); +static BITBOARD Nps(const BITBOARD nodes, const BITBOARD ms); +static void P(const char *format, ...); +static void Ok(); +static void Go(); +static void Token_add(const char *s); +static void Token_reset(); +static const char *Token_current(); +static void Token_pop(); +static bool Token_ok(); +static bool Token_is(const char *s); +static void Token_expect(const char *s); +static bool Token_next(const char *s); +static int Token_next_int(); +static void Hashtable_free_memory(); +static void Free_memory(); +static void Hashtable_set_size(const int usize /* MB */); +static void Hashtable_make_bigger(); +static void System(); +static void Print_version(); +static void Print_help(); +static void Command_isprime(); +static void Command_list(); +static void Add_prime(const int prime); +static int Last_prime(); +static bool Is_prime(const int prime); +static bool User_is_prime(const int prime); +static int Next_prime(); +static void Insert_primes(const int usize); +static void Init_primes(); +static void Bench(); +static int Nth_prime(const int prime_n); +static void Command_nthprime(); +static void Print_primes(const int usize); +static void FCP_commands(); +static void Init_tokens(int argc, char **argv); + +// !! i love you grandpa !! + +#endif // FAST_PRIMES_LL_H \ No newline at end of file diff --git a/makefile b/makefile index d3b3e86..8e04dcc 100644 --- a/makefile +++ b/makefile @@ -1,7 +1,7 @@ INSTALLDIR=/usr/games/ build: - gcc -Wall -O3 fast_primes_ll.c -o fast_primes_ll + gcc -Wall -O2 fast_primes_ll.c -o fast_primes_ll clean: rm -f fast_primes_ll