diff --git a/PerfectNumbers.Core.Tests/PrimesGeneratorTests.cs b/PerfectNumbers.Core.Tests/PrimesGeneratorTests.cs index 7f3cf81..ce8ae14 100644 --- a/PerfectNumbers.Core.Tests/PrimesGeneratorTests.cs +++ b/PerfectNumbers.Core.Tests/PrimesGeneratorTests.cs @@ -12,9 +12,9 @@ public class PrimesGeneratorTests var primes = PrimesGenerator.SmallPrimes; var squares = PrimesGenerator.SmallPrimesPow2; - primes[..5].Should().Equal(new ulong[] { 2UL, 3UL, 5UL, 7UL, 11UL }); + primes[..5].Should().Equal([2, 3, 5, 7, 11]); - squares[..5].Should().Equal(new ulong[] { 4UL, 9UL, 25UL, 49UL, 121UL }); + squares[..5].Should().Equal([4UL, 9UL, 25UL, 49UL, 121UL]); for (int i = 0; i < 5; i++) { diff --git a/PerfectNumbers.Core/PerfectNumberConstants.cs b/PerfectNumbers.Core/PerfectNumberConstants.cs index 9a8bec8..b8b6a40 100644 --- a/PerfectNumbers.Core/PerfectNumberConstants.cs +++ b/PerfectNumbers.Core/PerfectNumberConstants.cs @@ -3,7 +3,7 @@ namespace PerfectNumbers.Core; public static class PerfectNumberConstants { public const ulong BiggestKnownEvenPerfectP = 136279841UL; - public static readonly ulong PrimesLimit = 1_000_000; //(ulong)Array.MaxLength;// 1_000_000; + public static readonly uint PrimesLimit = 1_000_000; //(ulong)Array.MaxLength;// 1_000_000; // Maximum K for residue-based Mersenne test (q = 2*p*k + 1 up to this k) public static readonly UInt128 ResidueMaxK = 5_000_000UL; diff --git a/PerfectNumbers.Core/PrimeTester.cs b/PerfectNumbers.Core/PrimeTester.cs index 0d74ec2..6704d21 100644 --- a/PerfectNumbers.Core/PrimeTester.cs +++ b/PerfectNumbers.Core/PrimeTester.cs @@ -55,7 +55,7 @@ public sealed class PrimeTester(bool useInternal = false) else { var smallPrimeDivisorsLength = PrimesGenerator.SmallPrimes.Length; - ulong[] smallPrimeDivisors = PrimesGenerator.SmallPrimes; + uint[] smallPrimeDivisors = PrimesGenerator.SmallPrimes; ulong[] smallPrimeDivisorsMul = PrimesGenerator.SmallPrimesPow2; for (int i = 0; i < smallPrimeDivisorsLength; i++) { @@ -128,8 +128,8 @@ public sealed class PrimeTester(bool useInternal = false) // Per-accelerator GPU state for prime sieve (kernel + uploaded primes). private sealed class KernelState { - public Action, ArrayView, ArrayView> Kernel { get; } - public MemoryBuffer1D DevicePrimes { get; } + public Action, ArrayView, ArrayView> Kernel { get; } + public MemoryBuffer1D DevicePrimes { get; } private readonly Accelerator _accel; private readonly System.Collections.Concurrent.ConcurrentBag _scratchPool = new(); @@ -137,10 +137,10 @@ public sealed class PrimeTester(bool useInternal = false) { _accel = accelerator; // Compile once per accelerator and upload primes once. - Kernel = accelerator.LoadAutoGroupedStreamKernel, ArrayView, ArrayView>(SmallPrimeSieveKernel); + Kernel = accelerator.LoadAutoGroupedStreamKernel, ArrayView, ArrayView>(SmallPrimeSieveKernel); var primes = PrimesGenerator.SmallPrimes; - DevicePrimes = accelerator.Allocate1D(primes.Length); + DevicePrimes = accelerator.Allocate1D(primes.Length); DevicePrimes.View.CopyFromCPU(primes); } @@ -232,7 +232,7 @@ public sealed class PrimeTester(bool useInternal = false) // GPU kernel: small-prime sieve only. Returns 1 if passes sieve (probable prime), 0 otherwise. // TODO: Follow-up: consider integration with MR rounds for bases {2,3,5,7,11,13} to make it deterministic for 64-bit. - private static void SmallPrimeSieveKernel(Index1D index, ArrayView numbers, ArrayView smallPrimes, ArrayView results) + private static void SmallPrimeSieveKernel(Index1D index, ArrayView numbers, ArrayView smallPrimes, ArrayView results) { ulong n = numbers[index]; if (n <= 3UL) @@ -256,9 +256,9 @@ public sealed class PrimeTester(bool useInternal = false) } long len = smallPrimes.Length; - for (long i = 0; i < len; i++) + for (int i = 0; i < len; i++) { - ulong p = smallPrimes[(int)i]; + ulong p = smallPrimes[i]; if (p * p > n) { break; diff --git a/PerfectNumbers.Core/PrimesGenerator.cs b/PerfectNumbers.Core/PrimesGenerator.cs index 226b7c5..c84d5d6 100644 --- a/PerfectNumbers.Core/PrimesGenerator.cs +++ b/PerfectNumbers.Core/PrimesGenerator.cs @@ -2,18 +2,14 @@ namespace PerfectNumbers.Core; public static class PrimesGenerator { - private static ulong[]? _primes; - private static ulong[]? _primesPow2; - // private static UInt128[]? _primes128; - // private static UInt128[]? _primesPow2_128; + private static uint[]? _primes; + private static ulong[]? _primesPow2; - public static readonly ulong[] SmallPrimes = BuildSmallPrimesInternal(); + public static readonly uint[] SmallPrimes = BuildSmallPrimesInternal(); public static readonly ulong[] SmallPrimesPow2 = BuildSmallPrimesPow2Internal(); - // public static readonly UInt128[] SmallPrimes128 = BuildSmallPrimes128Internal(); - // public static readonly UInt128[] SmallPrimesPow2_128 = BuildSmallPrimesPow2_128Internal(); - - private static ulong[] BuildSmallPrimesInternal() + + private static uint[] BuildSmallPrimesInternal() { if (_primes == null) { @@ -33,74 +29,52 @@ public static class PrimesGenerator return _primesPow2!; } - // private static UInt128[] BuildSmallPrimes128Internal() - // { - // if (_primes == null) - // { - // BuildSmallPrimes(); - // } - - // return _primes128!; - // } - - // private static UInt128[] BuildSmallPrimesPow2_128Internal() - // { - // if (_primesPow2 == null) - // { - // BuildSmallPrimes(); - // } - - // return _primesPow2_128!; - // } - private static void BuildSmallPrimes() { - ulong limit = PerfectNumberConstants.PrimesLimit; - var primes = new ulong[limit]; - primes[0] = 2UL; - var primesPow2 = new ulong[limit]; - primesPow2[0] = 4UL; + uint limit = PerfectNumberConstants.PrimesLimit; + var primes = new uint[limit]; + primes[0] = 2; + var primesPow2 = new ulong[limit]; + primesPow2[0] = 4; - int j; - ulong i = 3UL, p, sqrt; - bool isPrime; - int primeIndex = 1; + int j; + uint i = 3, p, sqrt; + bool isPrime; + int primeIndex = 1; - for (; i <= limit; i += 2UL) - { - isPrime = true; - sqrt = (ulong)Math.Sqrt(i); - for (j = 0; j < primeIndex; j++) - { - p = primes[j]; - if (p > sqrt) - { - break; - } + for (; i <= limit; i += 2) + { + isPrime = true; + sqrt = (uint)Math.Sqrt(i); + for (j = 0; j < primeIndex; j++) + { + p = primes[j]; + if (p > sqrt) + { + break; + } - if (i % p == 0UL) - { - isPrime = false; - break; - } - } + if (i % p == 0UL) + { + isPrime = false; + break; + } + } - if (isPrime) - { - primes[primeIndex] = i; - primesPow2[primeIndex] = i * i; - primeIndex++; - } - } + if (isPrime) + { + primes[primeIndex] = i; + primesPow2[primeIndex] = i * i; + primeIndex++; + } + } - Array.Resize(ref primes, primeIndex); - Array.Resize(ref primesPow2, primeIndex); + Array.Resize(ref primes, primeIndex); + Array.Resize(ref primesPow2, primeIndex); - _primes = primes; - _primesPow2 = primesPow2; - // _primes128 = Array.ConvertAll(_primes, p => (UInt128)p); - // _primesPow2_128 = Array.ConvertAll(_primesPow2, p => (UInt128)p); + _primes = primes; + _primesPow2 = primesPow2; - return; - } + return; + } } \ No newline at end of file diff --git a/PerfectNumbers.Core/UInt128Extensions.cs b/PerfectNumbers.Core/UInt128Extensions.cs index 85670dd..d8c93d1 100644 --- a/PerfectNumbers.Core/UInt128Extensions.cs +++ b/PerfectNumbers.Core/UInt128Extensions.cs @@ -52,8 +52,8 @@ public static class UInt128Extensions } ulong order = (ulong)phi; - ulong[] smallPrimes = PrimesGenerator.SmallPrimes, - smallPrimesPow2 = PrimesGenerator.SmallPrimesPow2; + uint[] smallPrimes = PrimesGenerator.SmallPrimes; + ulong[] smallPrimesPow2 = PrimesGenerator.SmallPrimesPow2; int i = 0, primesLength = smallPrimes.Length; UInt128 cycle = MersenneDivisorCycles.GetCycle(q); @@ -100,7 +100,7 @@ public static class UInt128Extensions { UInt128 p, zero = UInt128.Zero; - ulong[] smallPrimes = PrimesGenerator.SmallPrimes; + uint[] smallPrimes = PrimesGenerator.SmallPrimes; ulong[] smallPrimesPow2 = PrimesGenerator.SmallPrimesPow2; ulong i, smallPrimesCount = (ulong)smallPrimes.Length; for (i = 0UL; i < smallPrimesCount; i++) diff --git a/PerfectNumbers.Core/ULongExtensions.cs b/PerfectNumbers.Core/ULongExtensions.cs index cc7df4d..9f3f68b 100644 --- a/PerfectNumbers.Core/ULongExtensions.cs +++ b/PerfectNumbers.Core/ULongExtensions.cs @@ -12,23 +12,22 @@ public static class ULongExtensions return 0UL; } - ulong order = q - 1UL; - ulong[] smallPrimes = PrimesGenerator.SmallPrimes; + ulong order = q - 1UL, prime, temp; + uint[] smallPrimes = PrimesGenerator.SmallPrimes; ulong[] smallPrimesPow2 = PrimesGenerator.SmallPrimesPow2; int i = 0, primesLength = smallPrimes.Length; - ulong prime, temp; UInt128 q128 = q, cycle = MersenneDivisorCycles.GetCycle(q128); for (; i < primesLength; i++) { - prime = smallPrimes[i]; if (smallPrimesPow2[i] > order) { break; } + prime = smallPrimes[i]; while (order % prime == 0UL) { temp = order / prime; @@ -63,7 +62,7 @@ public static class ULongExtensions { int i = 0; ulong p; - ulong[] smallPrimes = PrimesGenerator.SmallPrimes; + uint[] smallPrimes = PrimesGenerator.SmallPrimes; ulong[] smallPrimesPow2 = PrimesGenerator.SmallPrimesPow2; int len = smallPrimes.Length; for (; i < len; i++) @@ -388,7 +387,7 @@ public static class ULongExtensions { ulong value = exponent - 1UL; value >>= BitOperations.TrailingZeroCount(value); - ulong[] smallPrimes = PrimesGenerator.SmallPrimes; + uint[] smallPrimes = PrimesGenerator.SmallPrimes; ulong[] smallPrimesPow2 = PrimesGenerator.SmallPrimesPow2; int i = 1, smallPrimesLength = smallPrimes.Length; ulong prime;