diff --git a/README.md b/README.md index 40121c5..9e66b68 100644 --- a/README.md +++ b/README.md @@ -8,4 +8,4 @@ A fast prime number generator in C Language ```fast_primes_ll -h``` ### Usage -```fast_primes_ll -nth 10001 # Find out what's the 10,001st prime?``` +```fast_primes_ll -nth 10001 # Find out what's the 10,001st prime?``` \ No newline at end of file diff --git a/fast_primes_ll.c b/fast_primes_ll.c index 403b0cf..8827e65 100644 --- a/fast_primes_ll.c +++ b/fast_primes_ll.c @@ -20,7 +20,7 @@ #include "fast_primes_ll.h" #define NAME "fast_primes_ll" -#define VERSION "1.29" +#define VERSION "1.30" #define AUTHOR "Toni Helminen" #define MAX_TOKENS 32 @@ -34,17 +34,17 @@ typedef struct { int last_size; } PRIMES_T; -static char TOKENS[MAX_TOKENS][64] = {{0}}; -static int TOKENS_N = 0; -static int TOKENS_I = 0; -static PRIMES_T PRIMES = {0}; +static char TOKENS[MAX_TOKENS][64] = {{0}}; +static int TOKENS_N = 0; +static int TOKENS_I = 0; +static PRIMES_T PRIMES = {0}; -static inline /* <- make me faster! */ int Max(const int a, const int b) +static int Max(const int a, const int b) { return a > b ? a : b; } -static inline int Min(const int a, const int b) +static int Min(const int a, const int b) { return a < b ? a : b; } @@ -57,7 +57,9 @@ static bool Equal_strings(const char *a, const char *b) static BITBOARD Now() { static struct timeval t; + FCP_ASSERT(gettimeofday(&t, NULL) == 0) + return 1000 * t.tv_sec + t.tv_usec / 1000; } @@ -69,6 +71,7 @@ static BITBOARD Pps(const BITBOARD nodes, const BITBOARD ms) static void P(const char *format, ...) { va_list a; + va_start(a, format); vfprintf(stdout, format, a); va_end(a); @@ -112,9 +115,13 @@ static bool Token_is(const char *s) static void Token_expect(const char *s) { if ( ! Token_is(s)) { - P("{ Error: expected: '%s', but_found: '%s' }", s, Token_current()); + P("{ # Error"); + P(" expected = '%s',", s); + P(" but_found = '%s'", Token_current()); + P("}"); exit(0); } + Token_pop(); } @@ -129,20 +136,23 @@ static bool Token_next(const char *s) static int Token_next_int() { int r = 0; + if (Token_ok() && ! Token_is(";")) { // Assume number r = atoi(TOKENS[TOKENS_I]); Token_pop(); } + return r; } static void Primestable_free_memory() { - if (PRIMES.size > 0) { - free(PRIMES.primes); - PRIMES.primes = 0; - PRIMES.size = 0; - } + if (PRIMES.size <= 0) + return; + + free(PRIMES.primes); + PRIMES.primes = 0; + PRIMES.size = 0; } static void Free_memory() @@ -153,18 +163,25 @@ static void Free_memory() static void Primestable_set_size(const int usize /* MB */) { BITBOARD size = ULL(usize); + Primestable_free_memory(); + size = MAX(size, 1); size = MIN(size, 1024 * 1024); // 1 PB size = (1 << 20) * size; // To MB + PRIMES.size = 1; + while (PRIMES.size <= size) // Calculate needed memory in bytes PRIMES.size <<= 1; - PRIMES.size >>= 1; + + PRIMES.size >>= 1; PRIMES.primes_n = 0; - PRIMES.count = INT(PRIMES.size / sizeof(BITBOARD)); - PRIMES.primes = calloc(PRIMES.count, sizeof(BITBOARD)); + PRIMES.count = INT(PRIMES.size / sizeof(BITBOARD)); + PRIMES.primes = calloc(PRIMES.count, sizeof(BITBOARD)); + FCP_ASSERT(PRIMES.primes != NULL) // Make sure there is enough space + Init_primes(); } @@ -197,24 +214,25 @@ static void Print_version() static void Print_help() { P("{ # Help"); - P("}"); - P(""); + P(" Usage = fast_primes_ll [OPTION]... [PARAM]..."); + P("}\n"); + P("{ # General information"); - P(" what = fast_primes_ll is a fast prime number generator,"); - P(" usage = fast_primes_ll [COMMAND]... [OPTION]...,"); - P(" example = fast_primes_ll -nth 100001 # Find out what's the 10,001st prime?"); - P("}"); - P(""); + P(" what = fast_primes_ll is a fast prime number generator,"); + P(" usage = fast_primes_ll [COMMAND]... [OPTION]...,"); + P(" example = fast_primes_ll -nth 10001 # What's the 10,001st prime?"); + P("}\n"); + P("{ # Commands"); P(" -h(elp) = This help,"); - P(" -v(ersion) = Version,"); - P(" -bench = Benchmarking,"); - P(" -system = System info,"); + P(" -v(ersion) = Show version,"); + P(" -bench = Run benchmarks,"); + P(" -system = Show system info,"); P(" -is(prime) N = See if N is a prime,"); - P(" -nth(prime) N = Print Nth prime,"); - P(" -primes N = Print all primes up to N"); - P("}"); - P(""); + P(" -nth(prime) N = Show Nth prime,"); + P(" -primes N = Show all primes up to N"); + P("}\n"); + P("{ # Full source code, please see:"); P(" "); P("}"); @@ -224,15 +242,19 @@ static void Print_help() static void Command_isprime() { int n = Token_next_int(); + + P("{ # isprime"); if (Is_prime(n)) - P("{ Yes, %i is a prime number. }", n); + P(" result = Yes, %i is a prime number.", n); else - P("{ No, %i is not a prime number. }", n); + P(" result = No, %i is not a prime number.", n); + P("}"); } static BITBOARD Nth_prime(const int prime_n) { int n = Max(0, prime_n - 1); + if (prime_n == 0) return 0; if (n < PRIMES.primes_n) @@ -245,7 +267,8 @@ static BITBOARD Nth_prime(const int prime_n) static void Command_nthprime() { int n = Max(0, Token_next_int()); - P("{ # Results nth"); + + P("{ # nthprime"); P(" nth = %i,", n); P(" prime = %llu", Nth_prime(n)); P("}"); @@ -254,6 +277,7 @@ static void Command_nthprime() static void Command_primes() { int n = Max(2, Token_next_int()); + P("{ # First %i primes generated by %s v%s ", n, NAME, VERSION); Print_primes(n); Insert_primes(n); @@ -264,6 +288,7 @@ static void Add_prime(const BITBOARD prime) { if (PRIMES.primes_n >= PRIMES.count) Primestable_make_bigger(); + PRIMES.primes[PRIMES.primes_n] = prime; PRIMES.primes_n++; } @@ -271,11 +296,14 @@ static void Add_prime(const BITBOARD prime) static bool Is_prime_nogen(const BITBOARD prime) { int i; + if (prime < 2) return 1; + for (i = 0; i < PRIMES.primes_n && PRIMES.primes[i] * PRIMES.primes[i] <= prime; i++) if (prime % PRIMES.primes[i] == 0) return 0; + return 1; } @@ -283,9 +311,12 @@ static bool Is_prime(const BITBOARD prime) { int i, p; + if (prime <= 1) return 0; + for (i = 0; i < PRIMES.primes_n; i++) if (PRIMES.primes[i] == prime) return 1; + while (1) { p = Next_prime(); Add_prime(p); @@ -294,6 +325,7 @@ static bool Is_prime(const BITBOARD prime) if (p > prime) return 0; } + return 0; } @@ -305,11 +337,13 @@ static int Last_prime() static int Next_prime() { int candidate = Last_prime() + 1; + while (1) if (Is_prime_nogen(candidate)) return candidate; else candidate++; + FCP_ASSERT(0) } @@ -317,6 +351,7 @@ static void Insert_primes(const int n) { int i = 0; int l = PRIMES.primes_n; + while (PRIMES.primes_n < n) { Add_prime(Next_prime()); P(" %i = %llu%s", i + 1 + l, Last_prime(), i + 1 + l < n ? ",": ""); @@ -327,9 +362,12 @@ static void Insert_primes(const int n) static void Init_primes() { int i; + PRIMES.primes_n = 0; + Add_prime(2); Add_prime(3); + for (i = 0; i < 10; i++) Add_prime(Next_prime()); } @@ -338,18 +376,22 @@ static void Bench() { BITBOARD diff; BITBOARD start = Now(); - P("> Benching ...\n"); + + P("{ # Benching ...\n}\n"); + PRIMES.primes_n = 0; Add_prime(2); Add_prime(3); + while (PRIMES.primes_n < 1000000) { Add_prime(Next_prime()); if (PRIMES.primes_n % 100000 == 0) - P("{ progress = %i%% }", PRIMES.primes_n / 10000); + P("{ Progress = %i%% }", PRIMES.primes_n / 10000); } + diff = Now() - start; - P(""); - P("{ # Benchmarks"); + + P("\n{ # Benchmarks"); P(" time = %.3fs,", 0.001f * DOUBLE(diff)); P(" primes_per_second = %llu,", Pps(PRIMES.primes_n, diff)); P(" primes = %i", PRIMES.primes_n); @@ -360,6 +402,7 @@ static void Print_primes(const int usize) { int i; int n = Min(PRIMES.primes_n, usize); + for (i = 0; i < n; i++) P(" %i = %llu%s", i + 1, PRIMES.primes[i], i + 1 < n ? ",": ""); } @@ -367,6 +410,7 @@ static void Print_primes(const int usize) static void FCP_commands() { Token_expect(";"); + if (Token_next("v") || Token_next("version")) Print_version(); else if (Token_next("h") || Token_next("help")) @@ -381,7 +425,9 @@ static void FCP_commands() Command_primes(); else if (Token_next("nthprime") || Token_next("nth")) Command_nthprime(); + Token_expect(";"); + if (TOKENS_N <= 2) Print_help(); } @@ -389,25 +435,38 @@ static void FCP_commands() static void Init_tokens(int argc, char **argv) { int i; + Token_reset(); Token_add(";"); + for (i = 1 /* skip ./fast_primes_ll */; i < argc; i++) { if (argv[i][0] == '-' && strlen(argv[i]) > 1) Token_add(argv[i] + 1); else Token_add(argv[i]); } + Token_add(";"); } static void Ok() { + // Yes + FCP_ASSERT(Is_prime(37)); FCP_ASSERT(Is_prime(53)); - FCP_ASSERT( ! Is_prime(55)); - FCP_ASSERT( ! Is_prime(0)); + FCP_ASSERT(Is_prime(2131)); + + FCP_ASSERT(Nth_prime(17) == 59); FCP_ASSERT(Nth_prime(34) == 139); + + // Nope + + FCP_ASSERT( ! Is_prime(55)); + FCP_ASSERT( ! Is_prime(0)); + FCP_ASSERT( ! Is_prime(100)); + FCP_ASSERT( ! Is_prime(2220)); } static void Go() @@ -421,7 +480,10 @@ static void Go() int main(int argc, char **argv) { atexit(Free_memory); // No memory leaks + Init_tokens(argc, argv); + Go(); + return EXIT_SUCCESS; } diff --git a/fast_primes_ll.h b/fast_primes_ll.h index 80a87dd..d320ad1 100644 --- a/fast_primes_ll.h +++ b/fast_primes_ll.h @@ -10,15 +10,15 @@ #define BITBOARD unsigned long long -#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 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 int Max(const int a, const int b); +static int Min(const int a, const int b); static bool Equal_strings(const char *a, const char *b); static BITBOARD Now(); static BITBOARD Pps(const BITBOARD nodes, const BITBOARD ms);