Ensure GPU residue copies are synchronized and cover high divisor sets
This commit is contained in:
1 parent
633c94906a
commit
7449f146d9
7 files changed
+215
-2
No files matched your search
@@ -1,3 +1,5 @@
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using FluentAssertions;
|
||||
using PerfectNumbers.Core.Gpu;
|
||||
using Xunit;
|
||||
@@ -41,4 +43,69 @@ public class GpuUInt128Pow2Minus1ModTests
|
||||
results[i].Should().Be(single);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Pow2Minus1Mod_matches_bigint_for_large_mersenne_residue_candidates()
|
||||
{
|
||||
const ulong exponent = 107UL;
|
||||
const int limit = 500_000;
|
||||
UInt128 twoP = (UInt128)(2UL * exponent);
|
||||
|
||||
for (int k = 1; k <= limit; k++)
|
||||
{
|
||||
UInt128 q = checked(twoP * (UInt128)(ulong)k + UInt128.One);
|
||||
GpuUInt128 gpuRemainder = GpuUInt128.Pow2Minus1Mod(exponent, (GpuUInt128)q);
|
||||
|
||||
BigInteger bigQ = ToBigInteger(q);
|
||||
BigInteger bigPow = BigInteger.ModPow(new BigInteger(2), checked((int)exponent), bigQ);
|
||||
BigInteger bigRemainder = (bigPow - BigInteger.One) % bigQ;
|
||||
if (bigRemainder.Sign < 0)
|
||||
{
|
||||
bigRemainder += bigQ;
|
||||
}
|
||||
|
||||
gpuRemainder.Should().Be(ToGpuUInt128(bigRemainder));
|
||||
}
|
||||
|
||||
UInt128[] largeKs =
|
||||
{
|
||||
UInt128.Parse("1000000000000000"),
|
||||
UInt128.Parse("1000000000000000000"),
|
||||
UInt128.Parse("1000000000000000000000"),
|
||||
UInt128.Parse("99999999998192000000000")
|
||||
};
|
||||
|
||||
foreach (UInt128 kValue in largeKs)
|
||||
{
|
||||
UInt128 q = checked(twoP * kValue + UInt128.One);
|
||||
GpuUInt128 gpuRemainder = GpuUInt128.Pow2Minus1Mod(exponent, (GpuUInt128)q);
|
||||
|
||||
BigInteger bigQ = ToBigInteger(q);
|
||||
BigInteger bigPow = BigInteger.ModPow(new BigInteger(2), checked((int)exponent), bigQ);
|
||||
BigInteger bigRemainder = (bigPow - BigInteger.One) % bigQ;
|
||||
if (bigRemainder.Sign < 0)
|
||||
{
|
||||
bigRemainder += bigQ;
|
||||
}
|
||||
|
||||
gpuRemainder.Should().Be(ToGpuUInt128(bigRemainder));
|
||||
}
|
||||
}
|
||||
|
||||
private static BigInteger ToBigInteger(UInt128 value)
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[16];
|
||||
buffer.Clear();
|
||||
Unsafe.WriteUnaligned(ref buffer[0], value);
|
||||
return new BigInteger(buffer, isUnsigned: true, isBigEndian: false);
|
||||
}
|
||||
|
||||
private static GpuUInt128 ToGpuUInt128(BigInteger value)
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[16];
|
||||
buffer.Clear();
|
||||
value.TryWriteBytes(buffer, out _, isUnsigned: true, isBigEndian: false);
|
||||
UInt128 converted = Unsafe.ReadUnaligned<UInt128>(ref buffer[0]);
|
||||
return (GpuUInt128)converted;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user