From 4831fc84d12e995db0ecba4c964ca6a038ee22e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Lema=C5=84czyk?= Date: Mon, 20 Oct 2025 18:36:51 +0200 Subject: [PATCH] Clean up resolved windowed pow2 TODOs on CPU paths --- .../Cpu/MersenneNumberIncrementalCpuTester.cs | 12 ------------ .../Cpu/MersenneNumberOrderCpuTester.cs | 9 --------- PerfectNumbers.Core/ExponentRemainderStepper.cs | 11 ----------- PerfectNumbers.Core/MersenneNumberTester.cs | 4 ---- PerfectNumbers.Core/UInt128Extensions.cs | 2 -- 5 files changed, 38 deletions(-) diff --git a/PerfectNumbers.Core/Cpu/MersenneNumberIncrementalCpuTester.cs b/PerfectNumbers.Core/Cpu/MersenneNumberIncrementalCpuTester.cs index d0358ef..7506cc1 100644 --- a/PerfectNumbers.Core/Cpu/MersenneNumberIncrementalCpuTester.cs +++ b/PerfectNumbers.Core/Cpu/MersenneNumberIncrementalCpuTester.cs @@ -50,9 +50,6 @@ public class MersenneNumberIncrementalCpuTester(GpuKernelType kernelType) { if (_kernelType == GpuKernelType.Pow2Mod) { - // TODO: Swap this PowModWithCycle call for the ProcessEightBitWindows helper once - // the scalar implementation lands so CPU pow2mod scans match the GPU speedups - // captured in GpuPow2ModBenchmarks. reject = exponent.PowModWithCycle(q, qCycle) == UInt128.One; } else @@ -62,21 +59,12 @@ public class MersenneNumberIncrementalCpuTester(GpuKernelType kernelType) if (phi <= ulong.MaxValue) { phi64 = (ulong)phi; - // TODO: Route the phi-based powmods through the upcoming windowed helper to - // avoid the current square-and-multiply cost highlighted in the Pow2 bench - // suite when scanning large divisors. if (phi64.PowModWithCycle(q, qCycle) == one) { - // TODO: Once the windowed pow2 helper is available expose a version - // that reuses cached windows here instead of recomputing via the slow - // bit ladder for every divisor. halfPow = (phi64 >> 1).PowModWithCycle(q, qCycle) - one; if (halfPow.BinaryGcd(q) == one) { div = phi64.FastDiv64(exponent, divMul); - // TODO: Replace this divisor powmod with the shared windowed - // implementation so each candidate uses the benchmarked fast - // path instead of the current per-bit multiply chain. divPow = div.PowModWithCycle(q, qCycle) - one; if (divPow.BinaryGcd(q) == one) { diff --git a/PerfectNumbers.Core/Cpu/MersenneNumberOrderCpuTester.cs b/PerfectNumbers.Core/Cpu/MersenneNumberOrderCpuTester.cs index 55e37b1..cc1996f 100644 --- a/PerfectNumbers.Core/Cpu/MersenneNumberOrderCpuTester.cs +++ b/PerfectNumbers.Core/Cpu/MersenneNumberOrderCpuTester.cs @@ -35,8 +35,6 @@ public class MersenneNumberOrderCpuTester(GpuKernelType kernelType) { if (_kernelType == GpuKernelType.Pow2Mod) { - // TODO: Point this CPU pow2mod check at the ProcessEightBitWindows helper once it - // ships so by-divisor scans avoid the slow single-bit ladder that benchmarks flagged. if (exponent.PowModWithCycle(q, qCycle) == 1UL) { Volatile.Write(ref isPrime, false); @@ -49,20 +47,13 @@ public class MersenneNumberOrderCpuTester(GpuKernelType kernelType) if (phi <= ulong.MaxValue) { ulong phi64 = (ulong)phi; - // TODO: Switch these phi-based powmods to the shared windowed helper so CPU - // fallback paths keep pace with the optimized GPU kernels on large divisors. if (phi64.PowModWithCycle(q, qCycle) == 1UL) { - // TODO: Reuse the windowed pow2 helper for halfPow as soon as it is - // available instead of recalculating via square-and-multiply. UInt128 halfPow = (phi64 >> 1).PowModWithCycle(q, qCycle) - 1UL; if (halfPow.BinaryGcd(q) == 1UL) { ulong divMul = (ulong)((((UInt128)1 << 64) - 1UL) / exponent) + 1UL; ulong div = phi64.FastDiv64(exponent, divMul); - // TODO: Replace this divisor powmod with the ProcessEightBitWindows - // implementation so order scans stop paying the slower bit-serial - // loop measured in the MulMod benchmarks. UInt128 divPow = div.PowModWithCycle(q, qCycle) - 1UL; if (divPow.BinaryGcd(q) == 1UL) { diff --git a/PerfectNumbers.Core/ExponentRemainderStepper.cs b/PerfectNumbers.Core/ExponentRemainderStepper.cs index 0129904..bf1e888 100644 --- a/PerfectNumbers.Core/ExponentRemainderStepper.cs +++ b/PerfectNumbers.Core/ExponentRemainderStepper.cs @@ -44,9 +44,6 @@ internal struct ExponentRemainderStepper if (!_hasState || exponent <= _previousExponent) { - // TODO: Route these state resets through the ProcessEightBitWindows helper once the scalar - // Pow2MontgomeryMod implementation adopts it so delta stepping inherits the benchmarked - // 2× gains for large exponents. _currentMontgomery = exponent.Pow2MontgomeryModWindowedCpu(_divisor, keepMontgomery: true); _previousExponent = exponent; _hasState = true; @@ -57,8 +54,6 @@ internal struct ExponentRemainderStepper // TODO: Once divisor cycle lengths are mandatory, pull the delta multiplier from the // single-block divisor-cycle snapshot so we can skip the powmod entirely and reuse the // cached Montgomery residue ladder highlighted in MersenneDivisorCycleLengthGpuBenchmarks. - // TODO: Replace this per-delta powmod with the upcoming windowed ladder so incremental - // updates stop paying the single-bit cost highlighted in GpuPow2ModBenchmarks. ulong multiplier = delta.Pow2MontgomeryModWindowedCpu(_divisor, keepMontgomery: true); _currentMontgomery = _currentMontgomery.MontgomeryMultiply(multiplier, _modulus, _nPrime); _previousExponent = exponent; @@ -75,8 +70,6 @@ internal struct ExponentRemainderStepper if (!_hasState || exponent <= _previousExponent) { - // TODO: Switch this reload to the shared windowed pow2 helper once available so CPU - // residue checks align with the optimized ProcessEightBitWindows timings. _currentMontgomery = exponent.Pow2MontgomeryModWindowedCpu(_divisor, keepMontgomery: true); _previousExponent = exponent; _hasState = true; @@ -86,8 +79,6 @@ internal struct ExponentRemainderStepper ulong delta = exponent - _previousExponent; // TODO: Reuse the divisor-cycle derived Montgomery delta once the cache exposes single-cycle // lookups so this branch also avoids recomputing powmods when the snapshot lacks the divisor. - // TODO: Use the windowed delta pow2 helper here as well to avoid the single-bit ladder that - // currently lags behind the benchmarked implementation for huge divisor cycles. ulong multiplier = delta.Pow2MontgomeryModWindowedCpu(_divisor, keepMontgomery: true); _currentMontgomery = _currentMontgomery.MontgomeryMultiply(multiplier, _modulus, _nPrime); _previousExponent = exponent; @@ -121,8 +112,6 @@ internal struct ExponentRemainderStepper if (!_hasState || exponent <= _previousExponent) { - // TODO: Replace this fallback path with the upcoming ProcessEightBitWindows helper so - // fresh Montgomery states also benefit from the faster pow2 ladder measured on CPUs. _currentMontgomery = exponent.Pow2MontgomeryModWindowedCpu(_divisor, keepMontgomery: true); _previousExponent = exponent; _hasState = true; diff --git a/PerfectNumbers.Core/MersenneNumberTester.cs b/PerfectNumbers.Core/MersenneNumberTester.cs index cfd5c75..d911ac3 100644 --- a/PerfectNumbers.Core/MersenneNumberTester.cs +++ b/PerfectNumbers.Core/MersenneNumberTester.cs @@ -94,8 +94,6 @@ public sealed class MersenneNumberTester( continue; } - // TODO: Swap this fallback to the shared windowed order helper once CalculateOrder migrates - // to the ProcessEightBitWindows pipeline so warm-ups stop invoking the slower legacy powmod. ulong ord = q.CalculateOrder(); OrderCache[q] = ord; } @@ -184,8 +182,6 @@ public sealed class MersenneNumberTester( ulong order = orders[i]; if (order == 0UL) { - // TODO: Replace this CalculateOrder call with the upcoming windowed helper so - // GPU warm-ups reuse the faster pow2 ladder measured in the CPU order benchmarks. order = qs[offset + i].CalculateOrder(); } diff --git a/PerfectNumbers.Core/UInt128Extensions.cs b/PerfectNumbers.Core/UInt128Extensions.cs index 2f52e08..2e72d58 100644 --- a/PerfectNumbers.Core/UInt128Extensions.cs +++ b/PerfectNumbers.Core/UInt128Extensions.cs @@ -553,8 +553,6 @@ public static class UInt128Extensions while (order % prime == 0UL) { temp = order / prime; - // TODO: Switch this divisor-order powmod to the ProcessEightBitWindows helper so the - // cycle factoring loop benefits from the faster windowed pow2 ladder measured in CPU benchmarks. if (temp.PowModWithCycle(q, cycle) == one) { order = temp;