70 lines
1.6 KiB
C#
70 lines
1.6 KiB
C#
using System.Runtime.CompilerServices;
|
|
|
|
namespace PerfectNumbers.Core.Gpu;
|
|
|
|
internal static class KernelMathHelpers
|
|
{
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static ulong FastDiv64Gpu(ulong value, ulong divisor, ulong mul)
|
|
{
|
|
ulong quotient = GpuUInt128.MulHigh(value, mul);
|
|
GpuUInt128 remainder = new(0UL, value);
|
|
GpuUInt128 product = new(GpuUInt128.MulHigh(quotient, divisor), quotient * divisor);
|
|
remainder.Sub(product);
|
|
|
|
if (remainder.High != 0UL || remainder.Low >= divisor)
|
|
{
|
|
quotient++;
|
|
}
|
|
|
|
return quotient;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static ulong Mod128By64(GpuUInt128 value, ulong modulus)
|
|
{
|
|
ulong rem = 0UL;
|
|
ulong part = value.High;
|
|
for (int i = 0; i < 64; i++)
|
|
{
|
|
rem = (rem << 1) | (part >> 63);
|
|
if (rem >= modulus)
|
|
{
|
|
rem -= modulus;
|
|
}
|
|
part <<= 1;
|
|
}
|
|
|
|
part = value.Low;
|
|
for (int i = 0; i < 64; i++)
|
|
{
|
|
rem = (rem << 1) | (part >> 63);
|
|
if (rem >= modulus)
|
|
{
|
|
rem -= modulus;
|
|
}
|
|
part <<= 1;
|
|
}
|
|
|
|
return rem;
|
|
}
|
|
|
|
public static ulong CalculateCycleLengthSmall(ulong divisor)
|
|
{
|
|
if ((divisor & (divisor - 1UL)) == 0UL)
|
|
return 1UL;
|
|
|
|
ulong order = 1UL, pow = 2UL;
|
|
while (pow != 1UL)
|
|
{
|
|
pow <<= 1;
|
|
if (pow > divisor)
|
|
pow -= divisor;
|
|
|
|
order++;
|
|
}
|
|
|
|
return order;
|
|
}
|
|
}
|