Clarify per-divisor Montgomery recomputation
This commit is contained in:
1 parent
b2b71f705a
commit
f9d51efe94
2 files changed
+21
-43
No files matched your search
@@ -253,10 +253,6 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
Dictionary<ulong, MersenneDivisorCycles.FactorCacheEntry>? factorCache = null;
|
Dictionary<ulong, MersenneDivisorCycles.FactorCacheEntry>? factorCache = null;
|
||||||
DivisorCycleCache cycleCache = DivisorCycleCache.Shared;
|
DivisorCycleCache cycleCache = DivisorCycleCache.Shared;
|
||||||
|
|
||||||
ulong cachedModulus = 0UL;
|
|
||||||
MontgomeryDivisorData cachedDivisorData = default;
|
|
||||||
bool hasCachedDivisorData = false;
|
|
||||||
|
|
||||||
byte step10 = (byte)(step % 10UL);
|
byte step10 = (byte)(step % 10UL);
|
||||||
byte step8 = (byte)(step % 8UL);
|
byte step8 = (byte)(step % 8UL);
|
||||||
byte step5 = (byte)(step % 5UL);
|
byte step5 = (byte)(step % 5UL);
|
||||||
@@ -294,14 +290,10 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
|
|
||||||
if (admissible && (remainder8 == 1 || remainder8 == 7) && remainder3 != 0 && remainder5 != 0 && remainder7 != 0 && remainder11 != 0)
|
if (admissible && (remainder8 == 1 || remainder8 == 7) && remainder3 != 0 && remainder5 != 0 && remainder7 != 0 && remainder11 != 0)
|
||||||
{
|
{
|
||||||
if (!hasCachedDivisorData || cachedModulus != candidate)
|
// Each divisor appears only once in this monotonically increasing sequence, so
|
||||||
{
|
// rebuilding the Montgomery data per candidate avoids caching entries that we
|
||||||
cachedDivisorData = MontgomeryDivisorData.FromModulus(candidate);
|
// would never hit again.
|
||||||
cachedModulus = candidate;
|
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(candidate);
|
||||||
hasCachedDivisorData = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
MontgomeryDivisorData divisorData = cachedDivisorData;
|
|
||||||
ulong divisorCycle;
|
ulong divisorCycle;
|
||||||
|
|
||||||
if (candidate <= PerfectNumberConstants.MaxQForDivisorCycles)
|
if (candidate <= PerfectNumberConstants.MaxQForDivisorCycles)
|
||||||
@@ -410,10 +402,6 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
|
|
||||||
Dictionary<ulong, MersenneDivisorCycles.FactorCacheEntry>? factorCache = null;
|
Dictionary<ulong, MersenneDivisorCycles.FactorCacheEntry>? factorCache = null;
|
||||||
|
|
||||||
ulong cachedModulus = 0UL;
|
|
||||||
MontgomeryDivisorData cachedDivisorData = default;
|
|
||||||
bool hasCachedDivisorData = false;
|
|
||||||
|
|
||||||
const int RemainderTableSize = 6;
|
const int RemainderTableSize = 6;
|
||||||
byte[] remainderBuffer = ArrayPool<byte>.Shared.Rent(RemainderTableSize);
|
byte[] remainderBuffer = ArrayPool<byte>.Shared.Rent(RemainderTableSize);
|
||||||
byte[] stepBuffer = ArrayPool<byte>.Shared.Rent(RemainderTableSize);
|
byte[] stepBuffer = ArrayPool<byte>.Shared.Rent(RemainderTableSize);
|
||||||
@@ -483,6 +471,8 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
if (montgomeryBuilder != null && montgomeryBuffer != null)
|
if (montgomeryBuilder != null && montgomeryBuffer != null)
|
||||||
{
|
{
|
||||||
montgomerySpan = montgomeryBuffer.AsSpan(0, chunkCount);
|
montgomerySpan = montgomeryBuffer.AsSpan(0, chunkCount);
|
||||||
|
// Every candidate divisor is unique across the scan, so build Montgomery data
|
||||||
|
// for the current batch and drop it immediately instead of maintaining a cache.
|
||||||
montgomeryBuilder.Build(candidateSpan, montgomerySpan);
|
montgomeryBuilder.Build(candidateSpan, montgomerySpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -511,19 +501,16 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
divisorData = montgomerySpan[i];
|
divisorData = montgomerySpan[i];
|
||||||
if (divisorData.Modulus != candidate)
|
if (divisorData.Modulus != candidate)
|
||||||
{
|
{
|
||||||
|
// The GPU builder might skip entries when masks zero them out; recompute on the CPU
|
||||||
|
// without caching because divisors never repeat within a session.
|
||||||
divisorData = MontgomeryDivisorData.FromModulus(candidate);
|
divisorData = MontgomeryDivisorData.FromModulus(candidate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!hasCachedDivisorData || cachedModulus != candidate)
|
// Candidates remain unique even when GPU Montgomery support is disabled, so rebuild
|
||||||
{
|
// the divisor data inline instead of persisting unused cache entries.
|
||||||
cachedDivisorData = MontgomeryDivisorData.FromModulus(candidate);
|
divisorData = MontgomeryDivisorData.FromModulus(candidate);
|
||||||
cachedModulus = candidate;
|
|
||||||
hasCachedDivisorData = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
divisorData = cachedDivisorData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong divisorCycle;
|
ulong divisorCycle;
|
||||||
@@ -663,9 +650,6 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
{
|
{
|
||||||
private readonly MersenneNumberDivisorByDivisorCpuTester _owner;
|
private readonly MersenneNumberDivisorByDivisorCpuTester _owner;
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
private bool _hasCachedDivisorData;
|
|
||||||
private ulong _cachedDivisor;
|
|
||||||
private MontgomeryDivisorData _cachedDivisorData;
|
|
||||||
private ulong[]? _primeDeltas;
|
private ulong[]? _primeDeltas;
|
||||||
private ulong[]? _cycleRemainders;
|
private ulong[]? _cycleRemainders;
|
||||||
private ulong[]? _montgomeryDeltas;
|
private ulong[]? _montgomeryDeltas;
|
||||||
@@ -680,9 +664,6 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
internal void Reset()
|
internal void Reset()
|
||||||
{
|
{
|
||||||
_disposed = false;
|
_disposed = false;
|
||||||
_hasCachedDivisorData = false;
|
|
||||||
_cachedDivisor = 0UL;
|
|
||||||
_cachedDivisorData = default;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CheckDivisor(ulong divisor, in MontgomeryDivisorData divisorData, ulong divisorCycle, ReadOnlySpan<ulong> primes, Span<byte> hits)
|
public void CheckDivisor(ulong divisor, in MontgomeryDivisorData divisorData, ulong divisorCycle, ReadOnlySpan<ulong> primes, Span<byte> hits)
|
||||||
@@ -698,20 +679,15 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MontgomeryDivisorData cachedData = divisorData;
|
MontgomeryDivisorData effectiveDivisorData = divisorData;
|
||||||
if (cachedData.Modulus != divisor)
|
if (effectiveDivisorData.Modulus != divisor)
|
||||||
{
|
{
|
||||||
if (!_hasCachedDivisorData || _cachedDivisor != divisor)
|
// Each divisor surfaces only once across the monotonic scan, so rebuild the Montgomery data
|
||||||
{
|
// instead of retaining a cache entry that would never be reused within future checks.
|
||||||
_cachedDivisorData = MontgomeryDivisorData.FromModulus(divisor);
|
effectiveDivisorData = MontgomeryDivisorData.FromModulus(divisor);
|
||||||
_cachedDivisor = divisor;
|
|
||||||
_hasCachedDivisorData = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cachedData = _cachedDivisorData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong modulus = cachedData.Modulus;
|
ulong modulus = effectiveDivisorData.Modulus;
|
||||||
if (modulus <= 1UL || (modulus & 1UL) == 0UL)
|
if (modulus <= 1UL || (modulus & 1UL) == 0UL)
|
||||||
{
|
{
|
||||||
hits.Clear();
|
hits.Clear();
|
||||||
@@ -730,11 +706,11 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
|
|
||||||
if (_owner._deltasDevice == ByDivisorDeltasDevice.Cpu)
|
if (_owner._deltasDevice == ByDivisorDeltasDevice.Cpu)
|
||||||
{
|
{
|
||||||
CheckDivisorCpu(cachedData, divisorCycle, primes, hits);
|
CheckDivisorCpu(effectiveDivisorData, divisorCycle, primes, hits);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckDivisorGpu(cachedData, divisorCycle, primes, hits, length);
|
CheckDivisorGpu(effectiveDivisorData, divisorCycle, primes, hits, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CheckDivisorCpu(
|
private static void CheckDivisorCpu(
|
||||||
|
|||||||
@@ -412,6 +412,8 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
ulong divisorValue = filteredDivisorsSpan[i];
|
ulong divisorValue = filteredDivisorsSpan[i];
|
||||||
divisorSpan[i] = divisorValue;
|
divisorSpan[i] = divisorValue;
|
||||||
exponentSpan[i] = prime;
|
exponentSpan[i] = prime;
|
||||||
|
// Divisors never repeat while scanning the monotonically increasing sequence, so regenerate
|
||||||
|
// the Montgomery data for each entry rather than storing cache lines that no future batch would hit.
|
||||||
divisorDataSpan[i] = MontgomeryDivisorData.FromModulus(divisorValue);
|
divisorDataSpan[i] = MontgomeryDivisorData.FromModulus(divisorValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user