Add shift-first multiply helper and document benchmarks
This commit is contained in:
1 parent
40dff45a81
commit
84ebbed98b
15 files changed
+1333
-100
No files matched your search
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using FluentAssertions;
|
||||
using PerfectNumbers.Core;
|
||||
using PerfectNumbers.Core.Gpu;
|
||||
using Xunit;
|
||||
|
||||
namespace PerfectNumbers.Core.Tests;
|
||||
|
||||
[Trait("Category", "Fast")]
|
||||
public class PrimeOrderGpuHeuristicsTests
|
||||
{
|
||||
[Fact]
|
||||
public void TryPow2Mod_returns_overflow_for_marked_prime()
|
||||
{
|
||||
const ulong prime = 97UL;
|
||||
PrimeOrderGpuHeuristics.ClearAllOverflowForTesting();
|
||||
try
|
||||
{
|
||||
PrimeOrderGpuHeuristics.MarkOverflow(prime);
|
||||
|
||||
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(1UL, prime, out ulong remainder);
|
||||
|
||||
status.Should().Be(GpuPow2ModStatus.Overflow);
|
||||
remainder.Should().Be(0UL);
|
||||
}
|
||||
finally
|
||||
{
|
||||
PrimeOrderGpuHeuristics.ClearOverflow(prime);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryPow2Mod_returns_unavailable_for_unmarked_prime()
|
||||
{
|
||||
PrimeOrderGpuHeuristics.ClearAllOverflowForTesting();
|
||||
|
||||
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(1UL, 193UL, out ulong remainder);
|
||||
|
||||
status.Should().Be(GpuPow2ModStatus.Unavailable);
|
||||
remainder.Should().Be(0UL);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryPow2ModBatch_returns_overflow_for_marked_prime()
|
||||
{
|
||||
const ulong prime = 193UL;
|
||||
PrimeOrderGpuHeuristics.ClearAllOverflowForTesting();
|
||||
try
|
||||
{
|
||||
PrimeOrderGpuHeuristics.MarkOverflow(prime);
|
||||
|
||||
ulong[] remainders = new ulong[2];
|
||||
ulong[] exponents = { 1UL, 2UL };
|
||||
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2ModBatch(exponents, prime, remainders);
|
||||
|
||||
status.Should().Be(GpuPow2ModStatus.Overflow);
|
||||
remainders[0].Should().Be(0UL);
|
||||
remainders[1].Should().Be(0UL);
|
||||
}
|
||||
finally
|
||||
{
|
||||
PrimeOrderGpuHeuristics.ClearOverflow(prime);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryPow2ModBatch_returns_unavailable_and_clears_remainders_for_unmarked_prime()
|
||||
{
|
||||
PrimeOrderGpuHeuristics.ClearAllOverflowForTesting();
|
||||
|
||||
ulong[] remainders = { 123UL, 456UL };
|
||||
ulong[] exponents = { 1UL, 2UL };
|
||||
GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2ModBatch(exponents, 257UL, remainders);
|
||||
|
||||
status.Should().Be(GpuPow2ModStatus.Unavailable);
|
||||
remainders[0].Should().Be(0UL);
|
||||
remainders[1].Should().Be(0UL);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryPow2ModBatch_throws_when_remainder_span_is_too_small()
|
||||
{
|
||||
ulong[] remainders = new ulong[1];
|
||||
ulong[] exponents = { 1UL, 2UL };
|
||||
|
||||
Action act = () => PrimeOrderGpuHeuristics.TryPow2ModBatch(exponents, 5UL, remainders);
|
||||
|
||||
act.Should().Throw<ArgumentException>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Calculate_falls_back_to_cpu_when_gpu_overflow_is_marked()
|
||||
{
|
||||
const ulong prime = 7UL;
|
||||
PrimeOrderGpuHeuristics.ClearAllOverflowForTesting();
|
||||
try
|
||||
{
|
||||
PrimeOrderGpuHeuristics.MarkOverflow(prime);
|
||||
|
||||
PrimeOrderCalculator.PrimeOrderResult result = PrimeOrderCalculator.Calculate(prime, null, PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault);
|
||||
|
||||
result.Status.Should().Be(PrimeOrderCalculator.PrimeOrderStatus.Found);
|
||||
result.Order.Should().Be(3UL);
|
||||
}
|
||||
finally
|
||||
{
|
||||
PrimeOrderGpuHeuristics.ClearOverflow(prime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
using System.Numerics;
|
||||
using FluentAssertions;
|
||||
using PerfectNumbers.Core;
|
||||
using Xunit;
|
||||
|
||||
namespace PerfectNumbers.Core.Tests;
|
||||
|
||||
[Trait("Category", "Fast")]
|
||||
public class HeuristicArithmeticTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(0UL, 0UL, 1)]
|
||||
[InlineData(1UL, 3UL, 1)]
|
||||
[InlineData(ulong.MaxValue, 3UL, 3)]
|
||||
[InlineData(0xFFFF_FFFF_FFFF_FFFFUL, 5UL, 4)]
|
||||
[InlineData(0x8000_0000_0000_0000UL, 7UL, 5)]
|
||||
public void MultiplyShiftRight_matches_big_integer(ulong value, ulong multiplier, int shift)
|
||||
{
|
||||
BigInteger expected = ((BigInteger)value * multiplier) >> shift;
|
||||
|
||||
ulong result = HeuristicArithmetic.MultiplyShiftRight(value, multiplier, shift);
|
||||
|
||||
result.Should().Be((ulong)expected);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0UL, 0UL, 1)]
|
||||
[InlineData(1UL, 3UL, 1)]
|
||||
[InlineData(ulong.MaxValue, 3UL, 3)]
|
||||
[InlineData(0xFFFF_FFFF_FFFF_FFFFUL, 5UL, 4)]
|
||||
[InlineData(0x8000_0000_0000_0000UL, 7UL, 5)]
|
||||
[InlineData(0xDEAD_BEEF_DEAD_BEEFUL, 11UL, 63)]
|
||||
public void MultiplyShiftRightShiftFirst_matches_big_integer(ulong value, ulong multiplier, int shift)
|
||||
{
|
||||
BigInteger expected = ((BigInteger)value * multiplier) >> shift;
|
||||
|
||||
ulong result = HeuristicArithmetic.MultiplyShiftRightShiftFirst(value, multiplier, shift);
|
||||
|
||||
result.Should().Be((ulong)expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MultiplyShiftRightShiftFirst_returns_zero_when_shift_is_large()
|
||||
{
|
||||
HeuristicArithmetic.MultiplyShiftRightShiftFirst(ulong.MaxValue, 123UL, 64).Should().Be(0UL);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0UL, ulong.MaxValue, -1)]
|
||||
[InlineData(1UL, 1UL, -3)]
|
||||
public void MultiplyShiftRight_throws_when_shift_is_negative(ulong value, ulong multiplier, int shift)
|
||||
{
|
||||
Action act = () => HeuristicArithmetic.MultiplyShiftRight(value, multiplier, shift);
|
||||
|
||||
act.Should().Throw<ArgumentOutOfRangeException>();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0UL, ulong.MaxValue, -1)]
|
||||
[InlineData(1UL, 1UL, -3)]
|
||||
public void MultiplyShiftRightShiftFirst_throws_when_shift_is_negative(ulong value, ulong multiplier, int shift)
|
||||
{
|
||||
Action act = () => HeuristicArithmetic.MultiplyShiftRightShiftFirst(value, multiplier, shift);
|
||||
|
||||
act.Should().Throw<ArgumentOutOfRangeException>();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user