From 5a9e103bd50908bbbd4f5b69235b766d32ad0c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Lema=C5=84czyk?= Date: Wed, 29 Oct 2025 01:29:12 +0100 Subject: [PATCH] Replace heuristic sqrt with log2-based estimate --- .../HeuristicCombinedPrimeTester.cs | 29 +++++++++---------- PerfectNumbers.Core/HeuristicPrimeTester.cs | 29 +++++++++---------- 2 files changed, 26 insertions(+), 32 deletions(-) diff --git a/PerfectNumbers.Core/HeuristicCombinedPrimeTester.cs b/PerfectNumbers.Core/HeuristicCombinedPrimeTester.cs index 8d29efc..05c22a8 100644 --- a/PerfectNumbers.Core/HeuristicCombinedPrimeTester.cs +++ b/PerfectNumbers.Core/HeuristicCombinedPrimeTester.cs @@ -311,31 +311,28 @@ Cleanup: return n; } - ulong bit = 1UL << 62; - while (bit > n) + int log2 = BitOperations.Log2(n); + ulong estimate = 1UL << ((log2 + 1) >> 1); + ulong quotient = n / estimate; + + while (estimate > quotient) { - bit >>= 2; + estimate = (estimate + quotient) >> 1; + quotient = n / estimate; } - ulong result = 0UL; - ulong remainder = n; - while (bit != 0) + while (true) { - ulong candidate = result + bit; - if (remainder >= candidate) + ulong nextEstimate = estimate + 1UL; + if (nextEstimate > n / nextEstimate) { - remainder -= candidate; - result = (result >> 1) + bit; - } - else - { - result >>= 1; + break; } - bit >>= 2; + estimate = nextEstimate; } - return result; + return estimate; } private static ReadOnlySpan GetCombinedDivisors(byte nMod10) diff --git a/PerfectNumbers.Core/HeuristicPrimeTester.cs b/PerfectNumbers.Core/HeuristicPrimeTester.cs index d8fb2cd..d752147 100644 --- a/PerfectNumbers.Core/HeuristicPrimeTester.cs +++ b/PerfectNumbers.Core/HeuristicPrimeTester.cs @@ -436,31 +436,28 @@ Cleanup: return n; } - ulong bit = 1UL << 62; - while (bit > n) + int log2 = BitOperations.Log2(n); + ulong estimate = 1UL << ((log2 + 1) >> 1); + ulong quotient = n / estimate; + + while (estimate > quotient) { - bit >>= 2; + estimate = (estimate + quotient) >> 1; + quotient = n / estimate; } - ulong result = 0UL; - ulong remainder = n; - while (bit != 0) + while (true) { - ulong candidate = result + bit; - if (remainder >= candidate) + ulong nextEstimate = estimate + 1UL; + if (nextEstimate > n / nextEstimate) { - remainder -= candidate; - result = (result >> 1) + bit; - } - else - { - result >>= 1; + break; } - bit >>= 2; + estimate = nextEstimate; } - return result; + return estimate; } private static ReadOnlySpan GetGroupBEndingOrder(byte nMod10) => nMod10 switch