summaryrefslogtreecommitdiffstats
path: root/calc_pi.c
diff options
context:
space:
mode:
authorLibravatar bigfoot547 <[email protected]>2024-11-08 23:14:08 -0600
committerLibravatar bigfoot547 <[email protected]>2024-11-08 23:14:08 -0600
commit08cd39963c8257ec179cfdc7817c10db43571d92 (patch)
tree8479e7d03c87382d43f867c8cd646d3c6465c157 /calc_pi.c
add code
Diffstat (limited to 'calc_pi.c')
-rw-r--r--calc_pi.c110
1 files changed, 110 insertions, 0 deletions
diff --git a/calc_pi.c b/calc_pi.c
new file mode 100644
index 0000000..c3aa4da
--- /dev/null
+++ b/calc_pi.c
@@ -0,0 +1,110 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <math.h>
+
+#ifdef __GNUC__
+#define GCC_ALWAYS_INLINE inline __attribute__((always_inline))
+#else
+#define GCC_ALWAYS_INLINE inline
+#endif
+
+/* finds the popcount of a number without using a fancy intrinsic */
+GCC_ALWAYS_INLINE unsigned fake_pc(uint64_t pc) {
+ pc = (pc & UINT64_C(0x5555555555555555)) + ((pc & UINT64_C(0xAAAAAAAAAAAAAAAA)) >> 1);
+ pc = (pc & UINT64_C(0x3333333333333333)) + ((pc & UINT64_C(0xCCCCCCCCCCCCCCCC)) >> 2);
+ pc = (pc & UINT64_C(0x0F0F0F0F0F0F0F0F)) + ((pc & UINT64_C(0xF0F0F0F0F0F0F0F0)) >> 4);
+ pc = (pc & UINT64_C(0x00FF00FF00FF00FF)) + ((pc & UINT64_C(0xFF00FF00FF00FF00)) >> 8);
+ pc = (pc & UINT64_C(0x0000FFFF0000FFFF)) + ((pc & UINT64_C(0xFFFF0000FFFF0000)) >> 16);
+ pc = (pc & UINT64_C(0x00000000FFFFFFFF)) + ((pc & UINT64_C(0xFFFFFFFF00000000)) >> 32);
+ return (unsigned)pc; /* it will always be small enough to fit into an unsigned int (it won't be more than 63) */
+}
+
+GCC_ALWAYS_INLINE unsigned real_pc(uint64_t pc) {
+ return (unsigned)(__builtin_popcount((unsigned)(pc & 0xFFFFFFFF))
+ + __builtin_popcount((unsigned)(pc >> 32)));
+}
+
+#ifndef POPCOUNT
+#define POPCOUNT fake_pc
+#endif
+
+#define PRIME_LONG(v, _st) ((_st)[(v) >> 6])
+#define PRIME_SHIFT(v) ((v) & 63)
+#define PRIME_NUM(v, _st) ((PRIME_LONG(v, _st) >> PRIME_SHIFT(v)) & 1)
+
+unsigned long calc_pi(unsigned long in) {
+ uint64_t *storage;
+ unsigned long anum = in-1;
+ unsigned long nlongs = (anum + 63) >> 6;
+ unsigned long sum = 0;
+
+ storage = calloc(nlongs, sizeof(uint64_t));
+ if (!storage) {
+ fprintf(stderr, "Could not allocate space for %zu longs! (about %zu bytes): %s\n",
+ nlongs, nlongs * sizeof(uint64_t), strerror(errno));
+ abort();
+ }
+
+ /* fill storage with 1 bits */
+ for (size_t i = 0; i < nlongs - 1; ++i) {
+ storage[i] = ~UINT64_C(0);
+ }
+
+ storage[nlongs-1] = (UINT64_C(1) << (anum & 63)) - 1;
+
+ /* the sieve */
+ for (uint64_t n = 2; n * n <= in; ++n) {
+ if (!PRIME_NUM(n - 2, storage)) continue;
+
+ for (uint64_t m = n * 2; m <= in; m += n) {
+ PRIME_LONG(m - 2, storage) &= ~(UINT64_C(1) << PRIME_SHIFT(m - 2));
+ }
+ }
+
+ /* count up the primes */
+ for (size_t n = 0; n < nlongs; ++n) {
+ sum += POPCOUNT(storage[n]);
+ }
+
+ free(storage);
+
+ return sum;
+}
+
+unsigned long get_num(const char *str) {
+ char *end;
+ unsigned long ret = strtoul(str, &end, 10);
+
+ if (!*str || *end) {
+ fputs("Invalid number entered :(\n", stderr);
+ exit(EXIT_FAILURE);
+ }
+
+ if (ret < 2) {
+ fputs("Number must not be less than 2\n", stderr);
+ exit(EXIT_FAILURE);
+ }
+
+ return ret;
+}
+
+int main(int argc, char **argv) {
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s <num>\nWill print out the number of primes less than or equal to the supplied number.\n", argv[0] ? argv[0] : "(null)");
+ return EXIT_FAILURE;
+ }
+
+ unsigned long num = get_num(argv[1]);
+ unsigned long sum = calc_pi(num);
+
+ double v = (sum * log(num)) / num;
+
+ printf("%lu primes\n", sum);
+ printf("%lf num\n", v);
+
+ return EXIT_SUCCESS;
+}