Skip to content

Primality is decided by Miller-Rabin and Lucas-Lehmer, and finishes - #2232

Merged
Rafael-SOWNet merged 1 commit into
masterfrom
primality-by-miller-rabin-and-lucas-lehmer
Oct 30, 2026
Merged

Rafael-SOWNet merged 1 commit into
masterfrom
primality-by-miller-rabin-and-lucas-lehmer

Conversation

@Rafael-SOWNet

Copy link
Copy Markdown
Member

Fixes #2230. Raised by @Happypig375 on #2221.

Primes.IsPrime was trial division, decided only for a number that fits a long. It had three defects:

  • It hung. The loop was divisor * divisor <= value. Past divisor = 3037000499 the square overflows long and wraps negative, so for a prime between 3037000499² and 2^63 the loop ran until the divisor reached the number itself.
  • It was slow: about 1.5 · 10^9 divisions for a prime near 2^63, and 1.1 s for 2^61 - 1.
  • It left every number past 2^63 open: the Mersenne prime 2^89 - 1 and the composite 2^67 - 1 alike.

It is now:

  • Miller–Rabin to the first thirteen primes as bases, which is exact below ψ13 = 3317044064679887385961981, the least strong pseudoprime to all thirteen. The bound is from Sorenson and Webster, Strong pseudoprimes to twelve prime bases, Math. Comp. 86 (2017). The first twelve bases already suffice below 2^64.
  • Lucas–Lehmer for a Mersenne number 2^p - 1, after checking that p is prime, for p up to 5000.
  • Past ψ13, up to 4096 bits, a failed round still proves a number composite. A number that passes every round is left open, since passing is not a proof.

The compiled PP membership from #2223 calls the same test for any whole double; it had been left open past 2^63.

2.6.0 now
9223372036854775783 in PP does not finish; stopped after 60 s True, in 81 ms
(2^89 - 1) in PP left as written True
(10^30 + 1) in PP left as written False
(10^30 + 57) in PP, a prime past ψ13 left as written left as written

#2221's MembershipInASetOperationTest and its BREAKING-CHANGES entry used 2^89 - 1 as a number PP leaves open. Lucas–Lehmer now decides it, so both use 10^30 + 57 instead, with [0; 10^31] as an interval that holds it. The entry's values are re-measured on 2.6.0 and on this build.

Tests. PrimalityTest has:

  • 16 decided cases under a 30-second cap: the largest prime below 2^63, seven Mersenne numbers from 2^61 - 1 to 2^4423 - 1, the least strong pseudoprime to the first twelve bases, Carmichael numbers and base-2 strong pseudoprimes;
  • two cases that stay open;
  • every n below 200000, checked against a sieve;
  • 2000 random odd n below 10^12, checked against trial division.

Full suite 18080/0, interactive trio, AOT smoke 73/0, all frameworks build.

🤖 Generated with Claude Code

Primes.IsPrime was trial division, decided only for a number that fits a
long, and it had three defects:
- It hung. The loop was divisor * divisor <= value, and past
  divisor = 3037000499 the square overflows long and wraps negative. So
  for a prime between 3037000499^2 and 2^63 the loop ran until the
  divisor reached the number itself. 9223372036854775783 in PP, the
  largest prime below 2^63, did not finish on 2.6.0 or on master.
- It was slow: about 1.5e9 divisions for a prime near 2^63, and 1.1 s
  for 2^61 - 1.
- It left every number past 2^63 open, the Mersenne prime 2^89 - 1 and
  the composite 2^67 - 1 alike. @Happypig375 pointed to that on #2221.

It is now:
- Miller-Rabin to the first thirteen primes as bases. That is exact below
  psi13 = 3317044064679887385961981, the least strong pseudoprime to all
  thirteen (Sorenson and Webster, "Strong pseudoprimes to twelve prime
  bases", Math. Comp. 86 (2017)). The first twelve bases already suffice
  below 2^64.
- Lucas-Lehmer for a Mersenne number 2^p - 1, after checking that p is
  prime, for p up to 5000.
- Past psi13 and up to 4096 bits, a failed round still proves a number
  composite. A number that passes every round is left open, since
  passing is not a proof.

9223372036854775783 in PP is True in 81 ms, 2^89 - 1 is prime, and
10^30 + 1 is composite. 10^30 + 57, a prime past psi13, stays open, as
does psi13 itself.

The compiled PP membership calls the same test for any whole double. It
was left open past 2^63.

#2221's MembershipInASetOperationTest, and its BREAKING-CHANGES entry,
used 2^89 - 1 as a number PP leaves open. Lucas-Lehmer now decides it, so
both use 10^30 + 57 instead, with an interval that holds it, [0; 10^31],
and the entry's values re-measured on 2.6.0 and on this build.

PrimalityTest has 16 decided cases under a 30-second cap, among them the
largest prime below 2^63, seven Mersenne numbers from 2^61 - 1 to
2^4423 - 1, the least strong pseudoprime to the first twelve bases,
Carmichael numbers and base-2 strong pseudoprimes. It has two cases that
stay open, every n below 200000 against a sieve, and 2000 random odd n
below 10^12 against trial division.

Fixes #2230.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Rafael-SOWNet Rafael-SOWNet moved this from Todo to In review in AngouriMath Oct 30, 2026
@codecov

codecov Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.17647% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.67%. Comparing base (a4b7b74) to head (d947f85).

Files with missing lines Patch % Lines
...urces/AngouriMath/Functions/NumberTheory/Primes.cs 90.90% 1 Missing and 2 partials ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2232      +/-   ##
==========================================
- Coverage   86.67%   86.67%   -0.01%     
==========================================
  Files         310      310              
  Lines       67691    67717      +26     
  Branches    19634    19644      +10     
==========================================
+ Hits        58670    58691      +21     
- Misses       4905     4910       +5     
  Partials     4116     4116              
Flag Coverage Δ
cpp 37.77% <ø> (ø)
csharp 87.22% <91.17%> (-0.01%) ⬇️
fsharp 32.97% <ø> (ø)
interactive 40.72% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...ngouriMath/Core/Entity/Omni/Entity.Omni.Classes.cs 87.82% <ø> (ø)
Sources/AngouriMath/Numerics/NumberStatements.cs 93.33% <100.00%> (+3.33%) ⬆️
...urces/AngouriMath/Functions/NumberTheory/Primes.cs 80.95% <90.90%> (+3.26%) ⬆️

... and 6 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Rafael-SOWNet
Rafael-SOWNet merged commit 56e0946 into master Oct 30, 2026
35 checks passed
@github-project-automation github-project-automation Bot moved this from In review to Done in AngouriMath Oct 30, 2026
@Rafael-SOWNet
Rafael-SOWNet deleted the primality-by-miller-rabin-and-lucas-lehmer branch October 30, 2026 08:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Primality hangs below 2^63 and leaves 2^89 - 1 open: trial division where Miller-Rabin and Lucas-Lehmer decide

1 participant