175 lines
7.0 KiB
C#
175 lines
7.0 KiB
C#
using System.Runtime.CompilerServices;
|
|
using PerfectNumbers.Core.Gpu;
|
|
|
|
namespace PerfectNumbers.Core;
|
|
|
|
[method: MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
internal struct MersenneDivisorResidueStepper(ulong prime, in GpuUInt128 step, in GpuUInt128 firstDivisor)
|
|
{
|
|
private const ushort DecimalMaskWhenLastIsSeven = (1 << 3) | (1 << 7) | (1 << 9);
|
|
private const ushort DecimalMaskOtherwise = (1 << 1) | (1 << 3) | (1 << 7) | (1 << 9);
|
|
|
|
private readonly ushort decimalMask = (prime & 3UL) == 3UL ? DecimalMaskWhenLastIsSeven : DecimalMaskOtherwise;
|
|
private readonly byte step10 = ComputeModulo(step, 10, multiplier: 6);
|
|
private readonly byte step8 = (byte)(step.Low % 8UL);
|
|
private readonly byte step5 = ComputeModulo(step, 5, multiplier: 1);
|
|
private readonly byte step3 = ComputeModulo(step, 3, multiplier: 1);
|
|
private readonly byte step7 = ComputeModulo(step, 7, multiplier: 2);
|
|
private readonly byte step11 = ComputeModulo(step, 11, multiplier: 5);
|
|
private readonly byte step13 = ComputeModulo(step, 13, multiplier: 3);
|
|
private readonly byte step17 = ComputeModulo(step, 17, multiplier: 1);
|
|
private readonly byte step19 = ComputeModulo(step, 19, multiplier: 17);
|
|
|
|
private byte Remainder10 = ComputeModulo(firstDivisor, 10, multiplier: 6);
|
|
private byte Remainder8 = (byte)(firstDivisor.Low % 8UL);
|
|
private byte Remainder5 = ComputeModulo(firstDivisor, 5, multiplier: 1);
|
|
private byte Remainder3 = ComputeModulo(firstDivisor, 3, multiplier: 1);
|
|
private byte Remainder7 = ComputeModulo(firstDivisor, 7, multiplier: 2);
|
|
private byte Remainder11 = ComputeModulo(firstDivisor, 11, multiplier: 5);
|
|
private byte Remainder13 = ComputeModulo(firstDivisor, 13, multiplier: 3);
|
|
private byte Remainder17 = ComputeModulo(firstDivisor, 17, multiplier: 1);
|
|
private byte Remainder19 = ComputeModulo(firstDivisor, 19, multiplier: 17);
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public readonly bool IsAdmissible()
|
|
{
|
|
if (((decimalMask >> Remainder10) & 1) == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (Remainder8 != 1 && Remainder8 != 7)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (Remainder3 == 0 || Remainder5 == 0 || Remainder7 == 0 || Remainder11 == 0 || Remainder13 == 0 || Remainder17 == 0 || Remainder19 == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void Advance()
|
|
{
|
|
Remainder10 = AddMod(Remainder10, step10, 10);
|
|
Remainder8 = AddMod(Remainder8, step8, 8);
|
|
Remainder5 = AddMod(Remainder5, step5, 5);
|
|
Remainder3 = AddMod(Remainder3, step3, 3);
|
|
Remainder7 = AddMod(Remainder7, step7, 7);
|
|
Remainder11 = AddMod(Remainder11, step11, 11);
|
|
Remainder13 = AddMod(Remainder13, step13, 13);
|
|
Remainder17 = AddMod(Remainder17, step17, 17);
|
|
Remainder19 = AddMod(Remainder19, step19, 19);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
private static byte ComputeModulo(in GpuUInt128 value, byte modulus, byte multiplier)
|
|
{
|
|
ulong high = value.High % modulus;
|
|
ulong low = value.Low % modulus;
|
|
int result = (int)((high * multiplier) + low);
|
|
result %= modulus;
|
|
return (byte)result;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
private static byte AddMod(byte value, byte delta, byte modulus)
|
|
{
|
|
int sum = value + delta;
|
|
if (sum >= modulus)
|
|
{
|
|
sum -= modulus;
|
|
}
|
|
|
|
return (byte)sum;
|
|
}
|
|
}
|
|
|
|
[method: MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
internal struct MersenneDivisorResidueStepperDescending(ulong prime, in GpuUInt128 step, in GpuUInt128 firstDivisor)
|
|
{
|
|
private const ushort DecimalMaskWhenLastIsSeven = (1 << 3) | (1 << 7) | (1 << 9);
|
|
private const ushort DecimalMaskOtherwise = (1 << 1) | (1 << 3) | (1 << 7) | (1 << 9);
|
|
|
|
private readonly ushort decimalMask = (prime & 3UL) == 3UL ? DecimalMaskWhenLastIsSeven : DecimalMaskOtherwise;
|
|
private readonly byte step10 = ComputeModulo(step, 10, multiplier: 6);
|
|
private readonly byte step8 = (byte)(step.Low % 8UL);
|
|
private readonly byte step5 = ComputeModulo(step, 5, multiplier: 1);
|
|
private readonly byte step3 = ComputeModulo(step, 3, multiplier: 1);
|
|
private readonly byte step7 = ComputeModulo(step, 7, multiplier: 2);
|
|
private readonly byte step11 = ComputeModulo(step, 11, multiplier: 5);
|
|
private readonly byte step13 = ComputeModulo(step, 13, multiplier: 3);
|
|
private readonly byte step17 = ComputeModulo(step, 17, multiplier: 1);
|
|
private readonly byte step19 = ComputeModulo(step, 19, multiplier: 17);
|
|
|
|
private byte Remainder10 = ComputeModulo(firstDivisor, 10, multiplier: 6);
|
|
private byte Remainder8 = (byte)(firstDivisor.Low % 8UL);
|
|
private byte Remainder5 = ComputeModulo(firstDivisor, 5, multiplier: 1);
|
|
private byte Remainder3 = ComputeModulo(firstDivisor, 3, multiplier: 1);
|
|
private byte Remainder7 = ComputeModulo(firstDivisor, 7, multiplier: 2);
|
|
private byte Remainder11 = ComputeModulo(firstDivisor, 11, multiplier: 5);
|
|
private byte Remainder13 = ComputeModulo(firstDivisor, 13, multiplier: 3);
|
|
private byte Remainder17 = ComputeModulo(firstDivisor, 17, multiplier: 1);
|
|
private byte Remainder19 = ComputeModulo(firstDivisor, 19, multiplier: 17);
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public readonly bool IsAdmissible()
|
|
{
|
|
if (((decimalMask >> Remainder10) & 1) == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (Remainder8 != 1 && Remainder8 != 7)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (Remainder3 == 0 || Remainder5 == 0 || Remainder7 == 0 || Remainder11 == 0 || Remainder13 == 0 || Remainder17 == 0 || Remainder19 == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void Retreat()
|
|
{
|
|
Remainder10 = SubMod(Remainder10, step10, 10);
|
|
Remainder8 = SubMod(Remainder8, step8, 8);
|
|
Remainder5 = SubMod(Remainder5, step5, 5);
|
|
Remainder3 = SubMod(Remainder3, step3, 3);
|
|
Remainder7 = SubMod(Remainder7, step7, 7);
|
|
Remainder11 = SubMod(Remainder11, step11, 11);
|
|
Remainder13 = SubMod(Remainder13, step13, 13);
|
|
Remainder17 = SubMod(Remainder17, step17, 17);
|
|
Remainder19 = SubMod(Remainder19, step19, 19);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
private static byte ComputeModulo(in GpuUInt128 value, byte modulus, byte multiplier)
|
|
{
|
|
ulong high = value.High % modulus;
|
|
ulong low = value.Low % modulus;
|
|
int result = (int)((high * multiplier) + low);
|
|
result %= modulus;
|
|
return (byte)result;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
private static byte SubMod(byte value, byte delta, byte modulus)
|
|
{
|
|
int diff = value - delta;
|
|
if (diff < 0)
|
|
{
|
|
diff += modulus;
|
|
}
|
|
|
|
return (byte)diff;
|
|
}
|
|
}
|