% 10 operations replaces with UInt128/ulong.Mod10 methods
This commit is contained in:
1 parent
3e0102a404
commit
412ce4fd50
13 files changed
+256
-195
No files matched your search
@@ -0,0 +1,52 @@
|
|||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod10UInt128Benchmarks
|
||||||
|
{
|
||||||
|
[Params(3UL, 8191UL, 131071UL, 2147483647UL)]
|
||||||
|
public UInt128 Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public UInt128 StandardModulo()
|
||||||
|
{
|
||||||
|
return Value % 10UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ulong ModWithHighLowModulo()
|
||||||
|
{
|
||||||
|
// Split and fold under mod 10: 2^64 ≡ 6 (mod 10)
|
||||||
|
ulong value = (ulong)Value;
|
||||||
|
ulong high = value >> 64;
|
||||||
|
ulong low = value;
|
||||||
|
ulong highRem = high.Mod10();
|
||||||
|
ulong lowRem = low.Mod10();
|
||||||
|
ulong combined = lowRem + highRem * 6UL;
|
||||||
|
return combined.Mod10();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ulong ModWithLoopModulo()
|
||||||
|
{
|
||||||
|
UInt128 value = Value;
|
||||||
|
UInt128 zero = UInt128.Zero;
|
||||||
|
if (value == zero)
|
||||||
|
return 0UL;
|
||||||
|
|
||||||
|
ulong result = (ulong)value;
|
||||||
|
UInt128 high = value >> 64;
|
||||||
|
|
||||||
|
while (high != zero)
|
||||||
|
{
|
||||||
|
// 2^64 ≡ 6 (mod 10)
|
||||||
|
result = (result + (ulong)high * 6UL).Mod10();
|
||||||
|
high >>= 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.Mod10();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+2
-9
@@ -5,7 +5,7 @@ using PerfectNumbers.Core;
|
|||||||
namespace EvenPerfectBitScanner.Benchmarks;
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
[MemoryDiagnoser]
|
[MemoryDiagnoser]
|
||||||
public class Mod10Benchmarks
|
public class Mod10ULongBenchmarks
|
||||||
{
|
{
|
||||||
[Params(3UL, 8191UL, 131071UL, 2147483647UL)]
|
[Params(3UL, 8191UL, 131071UL, 2147483647UL)]
|
||||||
public ulong Value { get; set; }
|
public ulong Value { get; set; }
|
||||||
@@ -13,14 +13,7 @@ public class Mod10Benchmarks
|
|||||||
[Benchmark(Baseline = true)]
|
[Benchmark(Baseline = true)]
|
||||||
public ulong LegacyModulo()
|
public ulong LegacyModulo()
|
||||||
{
|
{
|
||||||
ulong value = Value;
|
return Value % 10UL;
|
||||||
UInt128 zero = UInt128.Zero;
|
|
||||||
if (value == zero)
|
|
||||||
{
|
|
||||||
return 0UL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value % 10UL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using PerfectNumbers.Core;
|
||||||
|
|
||||||
|
namespace EvenPerfectBitScanner.Benchmarks;
|
||||||
|
|
||||||
|
[MemoryDiagnoser]
|
||||||
|
public class Mod10_8_5_3StepsBenchmarks
|
||||||
|
{
|
||||||
|
[Params(3UL, 8191UL, 131071UL, 2147483647UL)]
|
||||||
|
public ulong Value { get; set; }
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public (ulong Mod10, ulong Mod8, ulong Mod3, ulong Mod5) LegacyModulo()
|
||||||
|
{
|
||||||
|
UInt128 value = Value;
|
||||||
|
ulong mod10 = (ulong)(value % 10UL) % 10UL;
|
||||||
|
ulong mod8 = (ulong)(value % 8UL);
|
||||||
|
ulong mod3 = (ulong)(value % 3UL);
|
||||||
|
ulong mod5 = (ulong)(value % 5UL);
|
||||||
|
return (mod10, mod8, mod3, mod5);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public (ulong Mod10, ulong Mod8, ulong Mod3, ulong Mod5) ModMethodModulo()
|
||||||
|
{
|
||||||
|
Value.Mod10_8_5_3(out ulong mod10, out ulong mod8, out ulong mod5, out ulong mod3);
|
||||||
|
// Step residues for q += 2*p
|
||||||
|
mod10 = mod10.Mod10();
|
||||||
|
return (mod10, mod8, mod3, mod5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1060,7 +1060,7 @@ internal static class Program
|
|||||||
// Optional: RLE blacklist and binary-threshold filters on p (safe only when configured)
|
// Optional: RLE blacklist and binary-threshold filters on p (safe only when configured)
|
||||||
if (p <= _rleHardMaxP)
|
if (p <= _rleHardMaxP)
|
||||||
{
|
{
|
||||||
if (!_rleOnlyLast7 || (p % 10UL) == 7UL)
|
if (!_rleOnlyLast7 || p.Mod10() == 7UL)
|
||||||
{
|
{
|
||||||
if (RleBlacklist.IsLoaded() && RleBlacklist.Matches(p))
|
if (RleBlacklist.IsLoaded() && RleBlacklist.Matches(p))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,10 +20,8 @@ public class MersenneNumberResidueCpuTester
|
|||||||
// Current residues
|
// Current residues
|
||||||
q.Mod10_8_5_3(out ulong r10, out ulong r8, out ulong r5, out ulong r3);
|
q.Mod10_8_5_3(out ulong r10, out ulong r8, out ulong r5, out ulong r3);
|
||||||
// Step residues for q += 2*p
|
// Step residues for q += 2*p
|
||||||
ulong step10 = (ulong)(twoP % 10UL) % 10UL;
|
twoP.Mod10_8_5_3(out ulong step10, out ulong step8, out ulong step5, out ulong step3);
|
||||||
ulong step8 = (ulong)(twoP % 8UL);
|
step10 = step10.Mod10();
|
||||||
ulong step3 = (ulong)(twoP % 3UL);
|
|
||||||
ulong step5 = (ulong)(twoP % 5UL);
|
|
||||||
|
|
||||||
// Allowed last-digit sets for q depending on last digit of M_p
|
// Allowed last-digit sets for q depending on last digit of M_p
|
||||||
// lastIsSeven == true => allow {7,9}
|
// lastIsSeven == true => allow {7,9}
|
||||||
|
|||||||
@@ -201,8 +201,8 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
|
|||||||
{
|
{
|
||||||
ulong idx = (ulong)index.X;
|
ulong idx = (ulong)index.X;
|
||||||
// residue automaton
|
// residue automaton
|
||||||
ulong step10 = ((exponent % 10UL) << 1) % 10UL;
|
ulong step10 = (exponent.Mod10() << 1).Mod10();
|
||||||
ulong r10 = q0m10 + (step10 * idx) % 10UL;
|
ulong r10 = q0m10 + (step10 * idx).Mod10();
|
||||||
r10 -= (r10 >= 10UL) ? 10UL : 0UL;
|
r10 -= (r10 >= 10UL) ? 10UL : 0UL;
|
||||||
bool shouldCheck = r10 != 5UL; // skip q ≡ 5 (mod 10); other residues handled by r8/r3/r5
|
bool shouldCheck = r10 != 5UL; // skip q ≡ 5 (mod 10); other residues handled by r8/r3/r5
|
||||||
if (shouldCheck)
|
if (shouldCheck)
|
||||||
@@ -358,7 +358,7 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
|
|||||||
ArrayView1D<ulong, Stride1D.Dense> smallPrimesPow2LastSeven)
|
ArrayView1D<ulong, Stride1D.Dense> smallPrimesPow2LastSeven)
|
||||||
{
|
{
|
||||||
ulong idx = (ulong)index.X;
|
ulong idx = (ulong)index.X;
|
||||||
ulong r10 = ra.Q0M10 + (ra.Step10 * idx) % 10UL; r10 -= (r10 >= 10UL) ? 10UL : 0UL;
|
ulong r10 = ra.Q0M10 + (ra.Step10 * idx).Mod10(); r10 -= (r10 >= 10UL) ? 10UL : 0UL;
|
||||||
bool shouldCheck = r10 != 5UL;
|
bool shouldCheck = r10 != 5UL;
|
||||||
if (shouldCheck)
|
if (shouldCheck)
|
||||||
{
|
{
|
||||||
@@ -489,7 +489,7 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
|
|||||||
ResidueAutomatonArgs ra, ArrayView<int> found, ArrayView1D<uint, Stride1D.Dense> smallCycles)
|
ResidueAutomatonArgs ra, ArrayView<int> found, ArrayView1D<uint, Stride1D.Dense> smallCycles)
|
||||||
{
|
{
|
||||||
ulong idx = (ulong)index.X;
|
ulong idx = (ulong)index.X;
|
||||||
ulong r10 = ra.Q0M10 + (ra.Step10 * idx) % 10UL; r10 -= (r10 >= 10UL) ? 10UL : 0UL;
|
ulong r10 = ra.Q0M10 + (ra.Step10 * idx).Mod10(); r10 -= (r10 >= 10UL) ? 10UL : 0UL;
|
||||||
bool shouldCheck = r10 != 5UL;
|
bool shouldCheck = r10 != 5UL;
|
||||||
if (shouldCheck)
|
if (shouldCheck)
|
||||||
{
|
{
|
||||||
@@ -573,7 +573,7 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
|
|||||||
ResidueAutomatonArgs ra, ArrayView<int> found, ArrayView1D<uint, Stride1D.Dense> smallCycles)
|
ResidueAutomatonArgs ra, ArrayView<int> found, ArrayView1D<uint, Stride1D.Dense> smallCycles)
|
||||||
{
|
{
|
||||||
ulong idx = (ulong)index.X;
|
ulong idx = (ulong)index.X;
|
||||||
ulong r10 = ra.Q0M10 + (ra.Step10 * idx) % 10UL; r10 -= (r10 >= 10UL) ? 10UL : 0UL;
|
ulong r10 = ra.Q0M10 + (ra.Step10 * idx).Mod10(); r10 -= (r10 >= 10UL) ? 10UL : 0UL;
|
||||||
bool shouldCheck = r10 != 5UL;
|
bool shouldCheck = r10 != 5UL;
|
||||||
if (shouldCheck)
|
if (shouldCheck)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ public class MersenneNumberIncrementalGpuTester(GpuKernelType kernelType, bool u
|
|||||||
|
|
||||||
var pow2Kernel = gpuLease.Pow2ModKernel;
|
var pow2Kernel = gpuLease.Pow2ModKernel;
|
||||||
var incKernel = gpuLease.IncrementalKernel;
|
var incKernel = gpuLease.IncrementalKernel;
|
||||||
ulong step10 = ((exponent % 10UL) << 1) % 10UL;
|
ulong step10 = (exponent.Mod10() << 1).Mod10();
|
||||||
ulong step8 = ((exponent & 7UL) << 1) & 7UL;
|
ulong step8 = ((exponent & 7UL) << 1) & 7UL;
|
||||||
ulong step3 = ((exponent % 3UL) << 1) % 3UL;
|
ulong step3 = ((exponent % 3UL) << 1) % 3UL;
|
||||||
ulong step5 = ((exponent % 5UL) << 1) % 5UL;
|
ulong step5 = ((exponent % 5UL) << 1) % 5UL;
|
||||||
|
|||||||
@@ -7,68 +7,68 @@ public class MersenneNumberOrderGpuTester(GpuKernelType kernelType, bool useGpuO
|
|||||||
private readonly GpuKernelType _kernelType = kernelType;
|
private readonly GpuKernelType _kernelType = kernelType;
|
||||||
private readonly bool _useGpuOrder = useGpuOrder;
|
private readonly bool _useGpuOrder = useGpuOrder;
|
||||||
|
|
||||||
public void Scan(ulong exponent, UInt128 twoP, bool lastIsSeven, UInt128 maxK, ref bool isPrime)
|
public void Scan(ulong exponent, UInt128 twoP, bool lastIsSeven, UInt128 maxK, ref bool isPrime)
|
||||||
{
|
{
|
||||||
var gpuLease = GpuKernelPool.GetKernel(_useGpuOrder);
|
var gpuLease = GpuKernelPool.GetKernel(_useGpuOrder);
|
||||||
var execution = gpuLease.EnterExecutionScope();
|
var execution = gpuLease.EnterExecutionScope();
|
||||||
var accelerator = gpuLease.Accelerator;
|
var accelerator = gpuLease.Accelerator;
|
||||||
var stream = gpuLease.Stream;
|
var stream = gpuLease.Stream;
|
||||||
int batchSize = GpuConstants.ScanBatchSize; // large batch improves GPU occupancy and avoids TDR
|
int batchSize = GpuConstants.ScanBatchSize; // large batch improves GPU occupancy and avoids TDR
|
||||||
UInt128 kStart = UInt128.One;
|
UInt128 kStart = UInt128.One;
|
||||||
ulong divMul = (ulong)((((UInt128)1 << 64) - UInt128.One) / exponent) + 1UL;
|
ulong divMul = (ulong)((((UInt128)1 << 64) - UInt128.One) / exponent) + 1UL;
|
||||||
byte last = lastIsSeven ? (byte)1 : (byte)0; // ILGPU kernels do not support bool parameters
|
byte last = lastIsSeven ? (byte)1 : (byte)0; // ILGPU kernels do not support bool parameters
|
||||||
|
|
||||||
var kernel = _kernelType switch
|
var kernel = _kernelType switch
|
||||||
{
|
{
|
||||||
GpuKernelType.Pow2Mod => gpuLease.Pow2ModOrderKernel,
|
GpuKernelType.Pow2Mod => gpuLease.Pow2ModOrderKernel,
|
||||||
_ => gpuLease.IncrementalOrderKernel,
|
_ => gpuLease.IncrementalOrderKernel,
|
||||||
};
|
};
|
||||||
|
|
||||||
var foundBuffer = accelerator.Allocate1D<int>(1);
|
var foundBuffer = accelerator.Allocate1D<int>(1);
|
||||||
UInt128 exponent128 = exponent;
|
UInt128 exponent128 = exponent;
|
||||||
exponent128.Mod10_8_5_3(out ulong exponentMod10, out ulong exponentMod8, out ulong exponentMod5, out ulong exponentMod3);
|
exponent128.Mod10_8_5_3(out ulong exponentMod10, out ulong exponentMod8, out ulong exponentMod5, out ulong exponentMod3);
|
||||||
ulong step10 = (exponentMod10 << 1) % 10UL;
|
ulong step10 = (exponentMod10 << 1).Mod10();
|
||||||
ulong step8 = (exponentMod8 << 1) & 7UL;
|
ulong step8 = (exponentMod8 << 1) & 7UL;
|
||||||
ulong step3 = (exponentMod3 << 1) % 3UL;
|
ulong step3 = (exponentMod3 << 1) % 3UL;
|
||||||
ulong step5 = (exponentMod5 << 1) % 5UL;
|
ulong step5 = (exponentMod5 << 1) % 5UL;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
UInt128 remaining;
|
UInt128 remaining;
|
||||||
int currentSize;
|
int currentSize;
|
||||||
int found = 0;
|
int found = 0;
|
||||||
while (kStart <= maxK && Volatile.Read(ref isPrime))
|
while (kStart <= maxK && Volatile.Read(ref isPrime))
|
||||||
{
|
{
|
||||||
remaining = maxK - kStart + 1UL;
|
remaining = maxK - kStart + 1UL;
|
||||||
currentSize = remaining > (UInt128)batchSize ? batchSize : (int)remaining;
|
currentSize = remaining > (UInt128)batchSize ? batchSize : (int)remaining;
|
||||||
foundBuffer.MemSetToZero();
|
foundBuffer.MemSetToZero();
|
||||||
// Precompute residue automaton bases for this batch
|
// Precompute residue automaton bases for this batch
|
||||||
UInt128 q0 = twoP * kStart + 1UL;
|
UInt128 q0 = twoP * kStart + 1UL;
|
||||||
q0.Mod10_8_5_3(out ulong q0m10, out ulong q0m8, out ulong q0m5, out ulong q0m3);
|
q0.Mod10_8_5_3(out ulong q0m10, out ulong q0m8, out ulong q0m5, out ulong q0m3);
|
||||||
var kernelArgs = new ResidueAutomatonArgs(q0m10, step10, q0m8, step8, q0m3, step3, q0m5, step5);
|
var kernelArgs = new ResidueAutomatonArgs(q0m10, step10, q0m8, step8, q0m3, step3, q0m5, step5);
|
||||||
|
|
||||||
|
|
||||||
// Ensure device has small cycles table for early rejections in order kernels
|
// Ensure device has small cycles table for early rejections in order kernels
|
||||||
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
|
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
|
||||||
kernel(stream, currentSize, exponent, (GpuUInt128)twoP, (GpuUInt128)kStart, last, divMul,
|
kernel(stream, currentSize, exponent, (GpuUInt128)twoP, (GpuUInt128)kStart, last, divMul,
|
||||||
kernelArgs, foundBuffer.View, smallCyclesView);
|
kernelArgs, foundBuffer.View, smallCyclesView);
|
||||||
|
|
||||||
stream.Synchronize();
|
stream.Synchronize();
|
||||||
foundBuffer.View.CopyToCPU(ref found, 1);
|
foundBuffer.View.CopyToCPU(ref found, 1);
|
||||||
if (found != 0)
|
if (found != 0)
|
||||||
{
|
{
|
||||||
Volatile.Write(ref isPrime, false);
|
Volatile.Write(ref isPrime, false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
kStart += (UInt128)currentSize;
|
kStart += (UInt128)currentSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
foundBuffer.Dispose();
|
foundBuffer.Dispose();
|
||||||
execution.Dispose();
|
execution.Dispose();
|
||||||
gpuLease.Dispose();
|
gpuLease.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,7 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
|
|||||||
UInt128 kStart = 1UL;
|
UInt128 kStart = 1UL;
|
||||||
byte last = lastIsSeven ? (byte)1 : (byte)0;
|
byte last = lastIsSeven ? (byte)1 : (byte)0;
|
||||||
var kernel = gpuLease.Pow2ModKernel;
|
var kernel = gpuLease.Pow2ModKernel;
|
||||||
ulong step10 = ((exponent % 10UL) << 1) % 10UL;
|
ulong step10 = (exponent.Mod10() << 1).Mod10();
|
||||||
ulong step8 = ((exponent & 7UL) << 1) & 7UL;
|
ulong step8 = ((exponent & 7UL) << 1) & 7UL;
|
||||||
ulong step3 = ((exponent % 3UL) << 1) % 3UL;
|
ulong step3 = ((exponent % 3UL) << 1) % 3UL;
|
||||||
ulong step5 = ((exponent % 5UL) << 1) % 5UL;
|
ulong step5 = ((exponent % 5UL) << 1) % 5UL;
|
||||||
|
|||||||
@@ -30,12 +30,12 @@ public sealed class MersenneResidueAutomaton
|
|||||||
_currentQ = _step + 1UL; // start at k = 1
|
_currentQ = _step + 1UL; // start at k = 1
|
||||||
|
|
||||||
// init residues
|
// init residues
|
||||||
Mod10R = Mod10(_currentQ);
|
Mod10R = _currentQ.Mod10();
|
||||||
Mod8R = Mod8(_currentQ);
|
Mod8R = Mod8(_currentQ);
|
||||||
Mod3R = Mod3(_currentQ);
|
Mod3R = Mod3(_currentQ);
|
||||||
Mod5R = Mod5(_currentQ);
|
Mod5R = Mod5(_currentQ);
|
||||||
|
|
||||||
_step10 = Mod10((ulong)(_step % 10UL));
|
_step10 = _step.Mod10().Mod10();
|
||||||
_step8 = (ulong)(_step & 7UL); // % 8
|
_step8 = (ulong)(_step & 7UL); // % 8
|
||||||
_step3 = Mod3(_step);
|
_step3 = Mod3(_step);
|
||||||
_step5 = Mod5(_step);
|
_step5 = Mod5(_step);
|
||||||
@@ -72,21 +72,6 @@ public sealed class MersenneResidueAutomaton
|
|||||||
Mod5R = r5;
|
Mod5R = r5;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static ulong Mod10(UInt128 value)
|
|
||||||
{
|
|
||||||
// Split and fold under mod 10: 2^64 ≡ 6 (mod 10)
|
|
||||||
ulong high = (ulong)(value >> 64);
|
|
||||||
ulong low = (ulong)value;
|
|
||||||
ulong highRem = Mod10(high);
|
|
||||||
ulong lowRem = Mod10(low);
|
|
||||||
ulong combined = lowRem + highRem * 6UL;
|
|
||||||
return Mod10(combined);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static ulong Mod10(ulong value) => value % 10UL;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static ulong Mod8(UInt128 value) => (ulong)value & 7UL;
|
private static ulong Mod8(UInt128 value) => (ulong)value & 7UL;
|
||||||
|
|
||||||
@@ -196,8 +181,8 @@ public sealed class Ending7Automaton
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static ulong AlignTo7(ulong start)
|
private static ulong AlignTo7(ulong start)
|
||||||
{
|
{
|
||||||
ulong r = start % 10UL;
|
ulong r = start.Mod10();
|
||||||
ulong add = (7UL + 10UL - r) % 10UL;
|
ulong add = (7UL + 10UL - r).Mod10();
|
||||||
return start + add;
|
return start + add;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ public sealed class PrimeTester(bool useInternal = false)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((n % 10UL) == 1UL && SharesFactorWithMaxExponent(n))
|
if (n.Mod10() == 1UL && SharesFactorWithMaxExponent(n))
|
||||||
{
|
{
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
@@ -266,7 +266,7 @@ public sealed class PrimeTester(bool useInternal = false)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((n % 10UL) == 1UL)
|
if (n.Mod10() == 1UL)
|
||||||
{
|
{
|
||||||
// Early reject special GCD heuristic with floor(log2 n)
|
// Early reject special GCD heuristic with floor(log2 n)
|
||||||
ulong m = 63UL - (ulong)ILGPU.Algorithms.XMath.LeadingZeroCount(n);
|
ulong m = 63UL - (ulong)ILGPU.Algorithms.XMath.LeadingZeroCount(n);
|
||||||
|
|||||||
@@ -5,109 +5,109 @@ namespace PerfectNumbers.Core;
|
|||||||
|
|
||||||
public static class PrimesGenerator
|
public static class PrimesGenerator
|
||||||
{
|
{
|
||||||
public static readonly uint[] SmallPrimes;
|
public static readonly uint[] SmallPrimes;
|
||||||
public static readonly ulong[] SmallPrimesPow2;
|
public static readonly ulong[] SmallPrimesPow2;
|
||||||
public static readonly uint[] SmallPrimesLastOne;
|
public static readonly uint[] SmallPrimesLastOne;
|
||||||
public static readonly ulong[] SmallPrimesPow2LastOne;
|
public static readonly ulong[] SmallPrimesPow2LastOne;
|
||||||
public static readonly uint[] SmallPrimesLastSeven;
|
public static readonly uint[] SmallPrimesLastSeven;
|
||||||
public static readonly ulong[] SmallPrimesPow2LastSeven;
|
public static readonly ulong[] SmallPrimesPow2LastSeven;
|
||||||
|
|
||||||
static PrimesGenerator()
|
static PrimesGenerator()
|
||||||
{
|
{
|
||||||
BuildSmallPrimes(
|
BuildSmallPrimes(
|
||||||
out SmallPrimes,
|
out SmallPrimes,
|
||||||
out SmallPrimesPow2,
|
out SmallPrimesPow2,
|
||||||
out SmallPrimesLastOne,
|
out SmallPrimesLastOne,
|
||||||
out SmallPrimesPow2LastOne,
|
out SmallPrimesPow2LastOne,
|
||||||
out SmallPrimesLastSeven,
|
out SmallPrimesLastSeven,
|
||||||
out SmallPrimesPow2LastSeven);
|
out SmallPrimesPow2LastSeven);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void BuildSmallPrimes(
|
private static void BuildSmallPrimes(
|
||||||
out uint[] all,
|
out uint[] all,
|
||||||
out ulong[] allPow2,
|
out ulong[] allPow2,
|
||||||
out uint[] lastOne,
|
out uint[] lastOne,
|
||||||
out ulong[] lastOnePow2,
|
out ulong[] lastOnePow2,
|
||||||
out uint[] lastSeven,
|
out uint[] lastSeven,
|
||||||
out ulong[] lastSevenPow2)
|
out ulong[] lastSevenPow2)
|
||||||
{
|
{
|
||||||
uint target = PerfectNumberConstants.PrimesLimit;
|
uint target = PerfectNumberConstants.PrimesLimit;
|
||||||
int targetInt = checked((int)target);
|
int targetInt = checked((int)target);
|
||||||
all = new uint[targetInt];
|
all = new uint[targetInt];
|
||||||
allPow2 = new ulong[targetInt];
|
allPow2 = new ulong[targetInt];
|
||||||
lastOne = new uint[targetInt];
|
lastOne = new uint[targetInt];
|
||||||
lastOnePow2 = new ulong[targetInt];
|
lastOnePow2 = new ulong[targetInt];
|
||||||
lastSeven = new uint[targetInt];
|
lastSeven = new uint[targetInt];
|
||||||
lastSevenPow2 = new ulong[targetInt];
|
lastSevenPow2 = new ulong[targetInt];
|
||||||
|
|
||||||
List<uint> primes = new(targetInt * 4 / 3 + 16);
|
List<uint> primes = new(targetInt * 4 / 3 + 16);
|
||||||
uint candidate = 2U;
|
uint candidate = 2U;
|
||||||
int allCount = 0;
|
int allCount = 0;
|
||||||
int lastOneCount = 0;
|
int lastOneCount = 0;
|
||||||
int lastSevenCount = 0;
|
int lastSevenCount = 0;
|
||||||
|
|
||||||
while (allCount < targetInt || lastOneCount < targetInt || lastSevenCount < targetInt)
|
while (allCount < targetInt || lastOneCount < targetInt || lastSevenCount < targetInt)
|
||||||
{
|
{
|
||||||
bool isPrime = true;
|
bool isPrime = true;
|
||||||
int primesCount = primes.Count;
|
int primesCount = primes.Count;
|
||||||
for (int i = 0; i < primesCount; i++)
|
for (int i = 0; i < primesCount; i++)
|
||||||
{
|
{
|
||||||
uint p = primes[i];
|
uint p = primes[i];
|
||||||
if (p * p > candidate)
|
if (p * p > candidate)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (candidate % p == 0U)
|
if (candidate % p == 0U)
|
||||||
{
|
{
|
||||||
isPrime = false;
|
isPrime = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPrime)
|
if (isPrime)
|
||||||
{
|
{
|
||||||
primes.Add(candidate);
|
primes.Add(candidate);
|
||||||
if (allCount < targetInt)
|
if (allCount < targetInt)
|
||||||
{
|
{
|
||||||
all[allCount] = candidate;
|
all[allCount] = candidate;
|
||||||
allPow2[allCount] = checked((ulong)candidate * candidate);
|
allPow2[allCount] = checked((ulong)candidate * candidate);
|
||||||
allCount++;
|
allCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (candidate != 2U)
|
if (candidate != 2U)
|
||||||
{
|
{
|
||||||
if (lastOneCount < targetInt && IsAllowedForLastOne(candidate))
|
if (lastOneCount < targetInt && IsAllowedForLastOne(candidate))
|
||||||
{
|
{
|
||||||
lastOne[lastOneCount] = candidate;
|
lastOne[lastOneCount] = candidate;
|
||||||
lastOnePow2[lastOneCount] = checked((ulong)candidate * candidate);
|
lastOnePow2[lastOneCount] = checked((ulong)candidate * candidate);
|
||||||
lastOneCount++;
|
lastOneCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastSevenCount < targetInt && IsAllowedForLastSeven(candidate))
|
if (lastSevenCount < targetInt && IsAllowedForLastSeven(candidate))
|
||||||
{
|
{
|
||||||
lastSeven[lastSevenCount] = candidate;
|
lastSeven[lastSevenCount] = candidate;
|
||||||
lastSevenPow2[lastSevenCount] = checked((ulong)candidate * candidate);
|
lastSevenPow2[lastSevenCount] = checked((ulong)candidate * candidate);
|
||||||
lastSevenCount++;
|
lastSevenCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
candidate = candidate == 2U ? 3U : candidate + 2U;
|
candidate = candidate == 2U ? 3U : candidate + 2U;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static bool IsAllowedForLastOne(uint prime)
|
private static bool IsAllowedForLastOne(uint prime)
|
||||||
{
|
{
|
||||||
uint mod10 = prime % 10U;
|
uint mod10 = prime % 10U;
|
||||||
return mod10 == 1U || mod10 == 3U || mod10 == 9U || prime == 7U || prime == 11U;
|
return mod10 == 1U || mod10 == 3U || mod10 == 9U || prime == 7U || prime == 11U;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static bool IsAllowedForLastSeven(uint prime)
|
private static bool IsAllowedForLastSeven(uint prime)
|
||||||
{
|
{
|
||||||
uint mod10 = prime % 10U;
|
uint mod10 = prime % 10U;
|
||||||
return mod10 == 3U || mod10 == 7U || mod10 == 9U || prime == 11U;
|
return mod10 == 3U || mod10 == 7U || mod10 == 9U || prime == 11U;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -215,11 +215,11 @@ public static class UInt128Extensions
|
|||||||
while (high != zero)
|
while (high != zero)
|
||||||
{
|
{
|
||||||
// 2^64 ≡ 6 (mod 10)
|
// 2^64 ≡ 6 (mod 10)
|
||||||
result = (result + (ulong)high * 6UL) % 10UL;
|
result = (result + (ulong)high * 6UL).Mod10();
|
||||||
high >>= 64;
|
high >>= 64;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result % 10UL;
|
return result.Mod10();
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
|||||||
Reference in new issue
Block a user