A header-only, C++20 implementation of the Miller–Rabin probabilistic primality test.
It automatically chooses deterministic sets of bases for 32‑bit and 64‑bit integers, making it both blazing fast and reliable for
all numbers up to
-
Templated – works with any unsigned integer type (
uint32_t,uint64_t,unsigned __int128, Boost multiprecision, etc.) -
Deterministic for small integers
-
$\leqslant 2^{32}$ : bases${2, 7, 61}$ -
$\leqslant 2^{64}$ : bases${2, 325, 9375, 28178, 450775, 9780504, 1795265022}$
-
-
Probabilistic fallback for larger arbitrary‑precision numbers (error
$\leqslant 4^{-k}$ ) -
Overflow‑safe modular multiplication (uses
__int128when available, otherwise binary method) - Header‑only – just drop the file into your project
-
C++20– requiresstd::unsigned_integralconcept (easily back‑portable toC++17)
- Factor odd
$n-1$ as$d\times 2^s$ with$d$ odd. - For a chosen base
$a$ , compute$x \equiv a^d \pmod{n}$ . - If
$x \equiv 1 \pmod{n}$ or$x \equiv -1 \pmod{n}$ , the number passes for this base. - Otherwise, repeatedly square
$x$ ($x \equiv x^2 \pmod{n}$ ).
If$x \equiv -1 \pmod{n}$ appears at some step$\to$ probable prime.
If no such value appears$\to$ composite (definitively). - Repeat with multiple bases to drive the error probability arbitrarily low.
#include "miller-rabin.h"
#include <iostream>
int main() {
std::cout << std::boolalpha;
// Small numbers – fully deterministic
std::cout << "13 prime? " << is_prime(13u) << '\n';
std::cout << "10007 prime? " << is_prime(10007ull) << '\n';
// 64‑bit numbers – still deterministic and instant
uint64_t big = 1234567890123456789ull;
std::cout << big << " prime? " << is_prime(big) << '\n';
// For wider types (e.g., __int128 or Boost) you can specify the number
// of random bases (default 20)
unsigned __int128 huge = (unsigned __int128)1 << 100;
std::cout << "2^100 + 277 prime? "
<< is_prime(huge + 277, 30) << '\n';
return 0;
}Any C++20 compiler will work:
g++ -std=c++20 -O2 example.cpp -o exampleMax n size |
Bases | Reference |
|---|---|---|
| 32‑bit | Jaeschke |
|
| 64‑bit | Jim Sinclair, |
Using these bases guarantees a correct answer with no false positives for all numbers in the range.
template <std::unsigned_integral T>
bool is_prime(T n, unsigned k = 20);-
$n$ – the integer to test (must be unsigned; conceptstd::unsigned_integral) -
$k$ – number of random bases to try (only used for types wider than 64‑bit; ignored for built‑in 32/64‑bit types) -
Returns
trueif$n$ is (probably) prime,falseif definitely composite.
To use the template with types like boost::multiprecision::cpp_int:
#include <boost/multiprecision/cpp_int.hpp>
using big_int = boost::multiprecision::cpp_int;
// Provide own mul_mod to avoid overflow (or rely on the portable version)
// The test method itself works unchanged.
std::cout << is_prime(big_int("1234567890123456789"), 25) << '\n';This project is provided under the MIT License. See the full license text in the source file.