{"id":35264106,"url":"https://github.com/arcuru/primes-cpp","last_synced_at":"2026-05-21T10:31:31.378Z","repository":{"id":137513617,"uuid":"65591660","full_name":"arcuru/primes-cpp","owner":"arcuru","description":"A compact primes library containing a highly optimized prime sieve and deterministic primality test.","archived":false,"fork":false,"pushed_at":"2016-09-10T05:54:07.000Z","size":21,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-01-12T14:19:36.743Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/arcuru.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2016-08-13T00:46:35.000Z","updated_at":"2016-08-13T00:47:40.000Z","dependencies_parsed_at":null,"dependency_job_id":"8d20632d-f7f4-41d4-85f2-bfdcd7cae52e","html_url":"https://github.com/arcuru/primes-cpp","commit_stats":null,"previous_names":["arcuru/primes-cpp"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/arcuru/primes-cpp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arcuru%2Fprimes-cpp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arcuru%2Fprimes-cpp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arcuru%2Fprimes-cpp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arcuru%2Fprimes-cpp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arcuru","download_url":"https://codeload.github.com/arcuru/primes-cpp/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arcuru%2Fprimes-cpp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33297518,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-21T02:57:32.698Z","status":"ssl_error","status_checked_at":"2026-05-21T02:57:31.990Z","response_time":62,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-12-30T09:48:04.212Z","updated_at":"2026-05-21T10:31:31.373Z","avatar_url":"https://github.com/arcuru.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Primes-cpp\nA compact primes library containing a highly optimized prime sieve and deterministic primality test.\n\nThis library exists mostly because I find the algorithm, and it's optimizations, interesting. There is a faster and more featured implementation that you can find at [kimwalisch/primesieve](https://github.com/kimwalisch/primesieve), but this small library has most of the benefits but with only a few hundred lines of code. This is a better starting point to understand why this can be fast.\n\n# The Sieve of Eratosthenes\nThis library uses [the Sieve of Eratosthenes](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes) algorithm to find primes in a range. The basic idea is that, rather than using trial division to find primes, you start with a large array denoting every possible number as a prime number, and mark numbers as not prime by checking all multiples.\n\nCheck out wikipedia to see it graphically, it's easier to understand that way. Here is a full implementation in Cpp code to find all primes up to N.\n\n```\nstd::vector\u003cbool\u003e is_prime(N, true);\nis_prime[0] = is_prime[1] = false; // By definition\nfor (int i = 2; i*i \u003c N; ++i) {\n  if (is_prime[i]) {\n    for (int j = i*i; j \u003c N; j += i) {\n      is_prime[j] = false;\n    }\n  }\n}\n```\n\nAfter this is run, we can check if any number `x` less than `N` is prime by checking `is_prime[x]`.\n\n# How it's fast\nThere are 4 different things that contribute to this implementation being very fast.\n\n## Cache-awareness (segmented sieving) \nThe largest speedup comes from handling the memory accesses in a sane manor.\n\nTo get an idea of what the memory access pattern looks like, consider trying to find all primes up to 10^9 (1,000,000). Since you need an array with space for every possible prime, this could use up to 1 GB of total space (10^9 bytes). Since the algorithm has to loop through the whole array for every prime less than the sqrt(10^9), that's going to take a long time.\n\nIf you break up the array into segments that fit into L1 cache, the memory access times drop considerably. By keeping a list of all the primes you need to sieve (every primes less than sqrt(N)) and sieving each of those on every segment, you can trade a few extra processor instructions (e.g. calculating which index you'll need to begin marking off at) for a far better memory access pattern.\n\n## Multi-threading\nThis goes almost without saying. Once you have the algorithm set up to sieve in segments for cache awareness, modifying it to spread the segments among the available processor threads is relatively trivial.\n\nThis implementation will read the number of available threads in the system and scale to that automatically, or it will accept threads as an optional input.\n\n## Wheel Factorization\nThis next bit starts to complicate the math a little bit.\n\nYou may have noticed that storing all possible places is rather inefficient, as the only even number is 2. So you could just store only places for all odd numbers and handle 2 as a special case.\n\nMore formally this technique is called [wheel factorization](https://en.wikipedia.org/wiki/Wheel_factorization).\n\nWhat you may *not* have realized is that we can extend this further by factoring out all the multiples of 3. Because the least common multiple of 2 and 3 is 6, we know that only numbers that fit the form `X % 6 == 1 || X % 6 == 5` can be prime. For every other possible value the numbers are divisible by either 2 or 3.\n\n```\nif X % 6 == 0, then X is divisible by both 2 and 3\nif X % 6 == 2, then X is divisible by 2\nif X % 6 == 3, then X is divisible by 3\nif X % 6 == 4, then X is divisible by 2\n```\n\nWe can extend this to `2, 3, 5` wheel factorization, wherein every prime (other than 2, 3, or 5) modulo 30 (2 * 3 * 5) is equal to one of the following.\n\n\u003e 1 7 11 13 17 19 23 29\n\nObviously this can be extended further, pre-sieving out many primes in advance. However this implementation sticks with `2, 3, 5` wheel factorization for reasons I explain below.\n\nNow we only need to store 8 possible primes per 30 values. If each place was being stored in a byte, we've reduced our memory requirements by almost 75%\n\n## Bitpacking\nObviously, we can compact our memory even further by using a bitpacking data structure. In my example code above I used std::vector\\\u003cbool\\\u003e, which is bitpacked, but with our wheel factorization the math going in and out may get a little complicated.\n\nIt's a bit more efficient to avoid the overhead and roll our own.\n\nNow the reason I stopped at `2, 3, 5` wheel factorization should become a bit more clear. There just happen to be *8* possible primes per 30 number segment, which packs nicely into a byte.\n\nAfter doing both (wheel factorization and bitpacking) we've reduced the memory requirements to find all primes up to 10^9 from 1 GB down to ~33 MB.\n\n# Building\n\nCmake is used for setting up the build system. On first run it will download a copy of [googletest](https://github.com/google/googletest) to use for unit testing.\n\n```\n\u003e mkdir build\n\u003e cd build\n\u003e cmake ..\n\u003e make\n```\n\nThis will build two binaries `unittest` and `benchmark`, that do exactly what their names imply. `benchmark` will take in a command line argument to test different size 'sieving', but is overall not very sophisticated.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farcuru%2Fprimes-cpp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farcuru%2Fprimes-cpp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farcuru%2Fprimes-cpp/lists"}