diff options
author | nthnluu <nate1299@me.com> | 2024-01-28 21:20:27 -0500 |
---|---|---|
committer | nthnluu <nate1299@me.com> | 2024-01-28 21:20:27 -0500 |
commit | c63f340d90800895f007de64b7d2d14624263331 (patch) | |
tree | 2c0849fa597dd6da831c8707b6f2603403778d7b /user/usr/bin/tests/prime.c |
Created student weenix repository
Diffstat (limited to 'user/usr/bin/tests/prime.c')
-rw-r--r-- | user/usr/bin/tests/prime.c | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/user/usr/bin/tests/prime.c b/user/usr/bin/tests/prime.c new file mode 100644 index 0000000..2e00bd1 --- /dev/null +++ b/user/usr/bin/tests/prime.c @@ -0,0 +1,107 @@ +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +typedef uint64_t bitmask_word_t; +#define BITMASK_WORD_BITWIDTH 64 +#define BITMASK_WORD_BITWIDTH_LOG2 6 +#define BITMASK_IDX(x) ((x) >> BITMASK_WORD_BITWIDTH_LOG2) +#define BITMASK_POS(x) ((x) & ~(~0UL << BITMASK_WORD_BITWIDTH_LOG2)) + +// 7 6 5 4 3 2 1 0 | 15 14 13 12 11 10 9 8 +#define BITMASK_POS_MASK(x) (1UL << BITMASK_POS(x)) + +#define BITMASK_MAX_IDX(x) (BITMASK_IDX((x)-1UL) + 1UL) +#define BITMASK_SIZE(x) (sizeof(bitmask_word_t) * BITMASK_MAX_IDX(x)) +#define GET_BIT(bitmask, x) \ + (((bitmask_word_t *)bitmask)[BITMASK_IDX(x)] & BITMASK_POS_MASK(x)) +#define SET_BIT(bitmask, x) \ + (((bitmask_word_t *)bitmask)[BITMASK_IDX(x)] |= BITMASK_POS_MASK(x)) +#define UNSET_BIT(bitmask, x) \ + (((bitmask_word_t *)bitmask)[BITMASK_IDX(x)] &= ~BITMASK_POS_MASK(x)) + +inline uint64_t *find_ne64(const uint64_t not, const uint64_t *start, + size_t count) +{ + uint64_t *ret; + __asm__ volatile( + "cld; repe; scasq; xor %%rax, %%rax; setz %%al; add %%rax, %%rcx;" + : "=D"(ret), "=c"(count) + : "A"(not), "D"(start), "c"(count) + : "cc"); + return count ? (ret - 1) : NULL; +} + +size_t next_set_bit(const bitmask_word_t *bitmask, size_t start, + size_t max_idx) +{ + size_t idx = BITMASK_IDX(start); + bitmask_word_t copy = (bitmask[idx++] >> BITMASK_POS(start)) - 1; + if (copy) + { + return start + __builtin_ctzl(copy); + } + if (idx < max_idx) + { + uint64_t *end = find_ne64(0, bitmask + idx, max_idx - idx); + if (end) + return (((end - bitmask) << BITMASK_WORD_BITWIDTH_LOG2) + + (unsigned)__builtin_ctzl(*end)); + } + return ~0UL; +} + +long compute_largest_prime(long n) +{ + if (n <= 1) + return -1; + if (n <= 3) + return n; + n = (n - 1) >> 1; + + bitmask_word_t *bitmask = + malloc(BITMASK_SIZE(n)); // GET_BIT(i) --> is 2 * i + 1 prime? + size_t max_idx = BITMASK_MAX_IDX(n); + memset(bitmask, 0xff, BITMASK_SIZE(n)); + + UNSET_BIT(bitmask, 0); + size_t prime_idx = 1; + + while (1) + { + long increment = (prime_idx << 1) | 1; // prime_idx * 2 + 1 + for (long multiple = prime_idx + increment; multiple <= n; + multiple += increment) + { + UNSET_BIT(bitmask, multiple); + } + // size_t next_prime_idx = prime_idx + 1; + // while (!GET_BIT(bitmask, next_prime_idx) && next_prime_idx <= + // n) + // next_prime_idx++; + + size_t next_prime_idx = next_set_bit(bitmask, prime_idx, max_idx); + + if (next_prime_idx > (size_t)n) + break; + prime_idx = next_prime_idx; + } + + free(bitmask); + return (prime_idx << 1) | 1; +} + +int main(int argc, char *argv[], char *envp[]) +{ + if (argc <= 1) + { + fprintf(stderr, + "USAGE: \"prime <n>\" to compute the largest prime <= n\n"); + exit(1); + } + long n = strtol(argv[1], NULL, 0); + fprintf(stdout, "%ld\n", compute_largest_prime(n)); + return 0; +} |