Various small optimizations and cleanups. Methods made static, where possible. Duplicated & slow PrimeTester.BinaryGcd implementation removed. Optimized version was used instead.
This commit is contained in:
1 parent
9939c5d562
commit
df04ba601c
4 files changed
+43
-105
No files matched your search
@@ -28,8 +28,8 @@ public class PrimeTesterBenchmarks
|
|||||||
|
|
||||||
PrimeOrderCalculatorAccelerator.WarmUp();
|
PrimeOrderCalculatorAccelerator.WarmUp();
|
||||||
// HeuristicGroupABPrimeTesterAccelerator.WarmUp();
|
// HeuristicGroupABPrimeTesterAccelerator.WarmUp();
|
||||||
_ = _heuristicTester.IsPrimeCpu(_candidates[0]);
|
_ = HeuristicPrimeTester.IsPrimeCpu(_candidates[0]);
|
||||||
_ = _heuristicTester.IsPrimeGpu(_candidates[0]);
|
_ = HeuristicPrimeTester.IsPrimeGpu(_candidates[0]);
|
||||||
_ = Prime.Numbers.IsPrime(_candidates[0]);
|
_ = Prime.Numbers.IsPrime(_candidates[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ public class PrimeTesterBenchmarks
|
|||||||
|
|
||||||
for (int i = 0; i < values.Length; i++)
|
for (int i = 0; i < values.Length; i++)
|
||||||
{
|
{
|
||||||
if (tester.IsPrimeCpu(values[i]))
|
if (HeuristicPrimeTester.IsPrimeCpu(values[i]))
|
||||||
{
|
{
|
||||||
primeCount++;
|
primeCount++;
|
||||||
}
|
}
|
||||||
@@ -60,7 +60,7 @@ public class PrimeTesterBenchmarks
|
|||||||
|
|
||||||
for (int i = 0; i < values.Length; i++)
|
for (int i = 0; i < values.Length; i++)
|
||||||
{
|
{
|
||||||
if (tester.IsPrimeGpu(values[i]))
|
if (HeuristicPrimeTester.IsPrimeGpu(values[i]))
|
||||||
{
|
{
|
||||||
primeCount++;
|
primeCount++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ using ILGPU.Runtime;
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using PerfectNumbers.Core.Gpu;
|
using PerfectNumbers.Core.Gpu;
|
||||||
using PerfectNumbers.Core.Gpu.Accelerators;
|
using PerfectNumbers.Core.Gpu.Accelerators;
|
||||||
using ILGPU;
|
|
||||||
|
|
||||||
namespace PerfectNumbers.Core;
|
namespace PerfectNumbers.Core;
|
||||||
|
|
||||||
@@ -266,14 +265,10 @@ public sealed class HeuristicCombinedPrimeTester
|
|||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static bool EvaluateWithOpenNumericFallback(ulong n)
|
private static bool EvaluateWithOpenNumericFallback(ulong n) => Prime.Numbers.IsPrime(n);
|
||||||
{
|
|
||||||
return Prime.Numbers.IsPrime(n);
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
}
|
internal static ulong ComputeHeuristicDivisorSquareLimit(ulong n) => n;
|
||||||
internal static ulong ComputeHeuristicDivisorSquareLimit(ulong n)
|
|
||||||
{
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ReadOnlySpan<ulong> GetCombinedDivisors(byte nMod10) => nMod10 switch
|
private static ReadOnlySpan<ulong> GetCombinedDivisors(byte nMod10) => nMod10 switch
|
||||||
{
|
{
|
||||||
@@ -470,9 +465,7 @@ public sealed class HeuristicCombinedPrimeTester
|
|||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static HeuristicDivisorEnumerator CreateHeuristicDivisorEnumerator(ulong maxDivisorSquare, byte nMod10, Span<HeuristicGroupBSequenceState> groupBBuffer)
|
internal static HeuristicDivisorEnumerator CreateHeuristicDivisorEnumerator(ulong maxDivisorSquare, byte nMod10, Span<HeuristicGroupBSequenceState> groupBBuffer)
|
||||||
{
|
=> new(maxDivisorSquare, nMod10, groupBBuffer);
|
||||||
return new HeuristicDivisorEnumerator(maxDivisorSquare, nMod10, groupBBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal struct HeuristicGroupBSequenceState
|
internal struct HeuristicGroupBSequenceState
|
||||||
{
|
{
|
||||||
@@ -480,9 +473,7 @@ public sealed class HeuristicCombinedPrimeTester
|
|||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static MersenneHeuristicDivisorEnumerator CreateMersenneDivisorEnumerator(ulong exponent, ulong maxDivisor)
|
internal static MersenneHeuristicDivisorEnumerator CreateMersenneDivisorEnumerator(ulong exponent, ulong maxDivisor)
|
||||||
{
|
=> new(exponent, maxDivisor);
|
||||||
return new MersenneHeuristicDivisorEnumerator(exponent, maxDivisor);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static HeuristicDivisorPreparation PrepareHeuristicDivisor(in HeuristicDivisorCandidate candidate)
|
internal static HeuristicDivisorPreparation PrepareHeuristicDivisor(in HeuristicDivisorCandidate candidate)
|
||||||
@@ -490,7 +481,7 @@ public sealed class HeuristicCombinedPrimeTester
|
|||||||
ulong divisor = candidate.Value;
|
ulong divisor = candidate.Value;
|
||||||
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(divisor);
|
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(divisor);
|
||||||
bool hasCycleHint = TryGetCycleLengthHint(divisor, out ulong cycleLength);
|
bool hasCycleHint = TryGetCycleLengthHint(divisor, out ulong cycleLength);
|
||||||
return new HeuristicDivisorPreparation(candidate, divisorData, cycleLength, hasCycleHint);
|
return new(candidate, divisorData, cycleLength, hasCycleHint);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@@ -588,7 +579,7 @@ public sealed class HeuristicCombinedPrimeTester
|
|||||||
ulong value = entry;
|
ulong value = entry;
|
||||||
byte ending = (byte)(value % 10UL);
|
byte ending = (byte)(value % 10UL);
|
||||||
ushort residue = (ushort)(value % Wheel210);
|
ushort residue = (ushort)(value % Wheel210);
|
||||||
candidate = new HeuristicDivisorCandidate(value, group, ending, 0, residue);
|
candidate = new(value, group, ending, 0, residue);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -691,7 +682,7 @@ public sealed class HeuristicCombinedPrimeTester
|
|||||||
}
|
}
|
||||||
|
|
||||||
ushort residue = (ushort)(value % Wheel210);
|
ushort residue = (ushort)(value % Wheel210);
|
||||||
return new HeuristicDivisorCandidate(value, group, ending, 0, residue);
|
return new(value, group, ending, 0, residue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,7 +68,8 @@ public sealed class HeuristicPrimeTester
|
|||||||
|
|
||||||
public static HeuristicPrimeTester Exclusive => _tester ??= new();
|
public static HeuristicPrimeTester Exclusive => _tester ??= new();
|
||||||
|
|
||||||
public bool IsPrimeCpu(ulong n)
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool IsPrimeCpu(ulong n)
|
||||||
{
|
{
|
||||||
byte nMod10 = (byte)n.Mod10();
|
byte nMod10 = (byte)n.Mod10();
|
||||||
ulong maxDivisorSquare = ComputeHeuristicDivisorSquareLimit(n);
|
ulong maxDivisorSquare = ComputeHeuristicDivisorSquareLimit(n);
|
||||||
@@ -82,19 +83,18 @@ public sealed class HeuristicPrimeTester
|
|||||||
return HeuristicTrialDivisionCpu(n, maxDivisorSquare, nMod10, includeGroupB);
|
return HeuristicTrialDivisionCpu(n, maxDivisorSquare, nMod10, includeGroupB);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsPrimeGpu(ulong n)
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool IsPrimeGpu(ulong n)
|
||||||
{
|
{
|
||||||
byte nMod10 = (byte)n.Mod10();
|
byte nMod10 = (byte)n.Mod10();
|
||||||
ulong maxDivisorSquare = ComputeHeuristicDivisorSquareLimit(n);
|
ulong maxDivisorSquare = ComputeHeuristicDivisorSquareLimit(n);
|
||||||
return IsPrimeGpu(n, maxDivisorSquare, nMod10);
|
return IsPrimeGpu(n, maxDivisorSquare, nMod10);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsPrimeGpu(ulong n, ulong maxDivisorSquare, byte nMod10)
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
{
|
public static bool IsPrimeGpu(ulong n, ulong maxDivisorSquare, byte nMod10) => HeuristicIsPrimeGpuCore(n, maxDivisorSquare, nMod10);
|
||||||
return HeuristicIsPrimeGpuCore(n, maxDivisorSquare, nMod10);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool HeuristicIsPrimeGpuCore(ulong n, ulong maxDivisorSquare, byte nMod10)
|
private static bool HeuristicIsPrimeGpuCore(ulong n, ulong maxDivisorSquare, byte nMod10)
|
||||||
{
|
{
|
||||||
// TODO: Is this condition ever met on the execution path in EvenPerfectBitScanner?
|
// TODO: Is this condition ever met on the execution path in EvenPerfectBitScanner?
|
||||||
if (maxDivisorSquare < 9UL)
|
if (maxDivisorSquare < 9UL)
|
||||||
@@ -133,7 +133,7 @@ public sealed class HeuristicPrimeTester
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong divisor = (ulong)groupADivisors[groupAIndex];
|
ulong divisor = groupADivisors[groupAIndex];
|
||||||
if (n % divisor == 0UL)
|
if (n % divisor == 0UL)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -186,7 +186,7 @@ public sealed class HeuristicPrimeTester
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong divisor = (ulong)groupADivisors[groupAIndex];
|
ulong divisor = groupADivisors[groupAIndex];
|
||||||
if (n % divisor == 0UL)
|
if (n % divisor == 0UL)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -240,7 +240,7 @@ public sealed class HeuristicPrimeTester
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private bool HeuristicTrialDivisionGpuDetectsDivisor(ulong n, ulong maxDivisorSquare, byte nMod10)
|
private static bool HeuristicTrialDivisionGpuDetectsDivisor(ulong n, ulong maxDivisorSquare, byte nMod10)
|
||||||
{
|
{
|
||||||
// GpuPrimeWorkLimiter.Acquire();
|
// GpuPrimeWorkLimiter.Acquire();
|
||||||
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
|
||||||
@@ -321,17 +321,11 @@ public sealed class HeuristicPrimeTester
|
|||||||
return compositeDetected;
|
return compositeDetected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static bool EvaluateWithOpenNumericFallback(ulong n) => Prime.Numbers.IsPrime(n);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static bool EvaluateWithOpenNumericFallback(ulong n)
|
internal static ulong ComputeHeuristicDivisorSquareLimit(ulong n) => n;
|
||||||
{
|
|
||||||
return Prime.Numbers.IsPrime(n);
|
|
||||||
}
|
|
||||||
internal static ulong ComputeHeuristicDivisorSquareLimit(ulong n)
|
|
||||||
{
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ReadOnlySpan<byte> GetGroupBEndingOrder(byte nMod10) => nMod10 switch
|
private static ReadOnlySpan<byte> GetGroupBEndingOrder(byte nMod10) => nMod10 switch
|
||||||
{
|
{
|
||||||
@@ -339,7 +333,7 @@ public sealed class HeuristicPrimeTester
|
|||||||
3 => GroupBEndingOrderMod3,
|
3 => GroupBEndingOrderMod3,
|
||||||
7 => GroupBEndingOrderMod7,
|
7 => GroupBEndingOrderMod7,
|
||||||
9 => GroupBEndingOrderMod9,
|
9 => GroupBEndingOrderMod9,
|
||||||
_ => ReadOnlySpan<byte>.Empty,
|
_ => [],
|
||||||
};
|
};
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@@ -415,19 +409,19 @@ public sealed class HeuristicPrimeTester
|
|||||||
private static ReadOnlySpan<uint> GetGroupBDivisors(byte ending) => ending switch
|
private static ReadOnlySpan<uint> GetGroupBDivisors(byte ending) => ending switch
|
||||||
{
|
{
|
||||||
1 => DivisorGenerator.SmallPrimesLastOneWithoutLastThree,
|
1 => DivisorGenerator.SmallPrimesLastOneWithoutLastThree,
|
||||||
3 => ReadOnlySpan<uint>.Empty,
|
3 => [],
|
||||||
7 => DivisorGenerator.SmallPrimesLastSevenWithoutLastThree,
|
7 => DivisorGenerator.SmallPrimesLastSevenWithoutLastThree,
|
||||||
9 => DivisorGenerator.SmallPrimesLastNineWithoutLastThree,
|
9 => DivisorGenerator.SmallPrimesLastNineWithoutLastThree,
|
||||||
_ => ReadOnlySpan<uint>.Empty,
|
_ => [],
|
||||||
};
|
};
|
||||||
|
|
||||||
private static ReadOnlySpan<ulong> GetGroupBDivisorSquares(byte ending) => ending switch
|
private static ReadOnlySpan<ulong> GetGroupBDivisorSquares(byte ending) => ending switch
|
||||||
{
|
{
|
||||||
1 => DivisorGenerator.SmallPrimesPow2LastOneWithoutLastThree,
|
1 => DivisorGenerator.SmallPrimesPow2LastOneWithoutLastThree,
|
||||||
3 => ReadOnlySpan<ulong>.Empty,
|
3 => [],
|
||||||
7 => DivisorGenerator.SmallPrimesPow2LastSevenWithoutLastThree,
|
7 => DivisorGenerator.SmallPrimesPow2LastSevenWithoutLastThree,
|
||||||
9 => DivisorGenerator.SmallPrimesPow2LastNineWithoutLastThree,
|
9 => DivisorGenerator.SmallPrimesPow2LastNineWithoutLastThree,
|
||||||
_ => ReadOnlySpan<ulong>.Empty,
|
_ => [],
|
||||||
};
|
};
|
||||||
|
|
||||||
private static int InitializeGroupBStates(byte nMod10, Span<HeuristicGroupBSequenceState> buffer)
|
private static int InitializeGroupBStates(byte nMod10, Span<HeuristicGroupBSequenceState> buffer)
|
||||||
@@ -444,16 +438,11 @@ public sealed class HeuristicPrimeTester
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static HeuristicDivisorEnumerator CreateHeuristicDivisorEnumerator(ulong maxDivisorSquare, byte nMod10, Span<HeuristicGroupBSequenceState> groupBBuffer)
|
internal static HeuristicDivisorEnumerator CreateHeuristicDivisorEnumerator(ulong maxDivisorSquare, byte nMod10, Span<HeuristicGroupBSequenceState> groupBBuffer) => new(maxDivisorSquare, nMod10, groupBBuffer);
|
||||||
{
|
|
||||||
return new HeuristicDivisorEnumerator(maxDivisorSquare, nMod10, groupBBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static MersenneHeuristicDivisorEnumerator CreateMersenneDivisorEnumerator(ulong exponent, ulong maxDivisor)
|
internal static MersenneHeuristicDivisorEnumerator CreateMersenneDivisorEnumerator(ulong exponent, ulong maxDivisor)
|
||||||
{
|
=> new(exponent, maxDivisor);
|
||||||
return new MersenneHeuristicDivisorEnumerator(exponent, maxDivisor);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static HeuristicDivisorPreparation PrepareHeuristicDivisor(in HeuristicDivisorCandidate candidate)
|
internal static HeuristicDivisorPreparation PrepareHeuristicDivisor(in HeuristicDivisorCandidate candidate)
|
||||||
@@ -611,25 +600,18 @@ public sealed class HeuristicPrimeTester
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
internal struct HeuristicGroupBSequenceState
|
internal struct HeuristicGroupBSequenceState(byte ending, byte priorityIndex)
|
||||||
{
|
{
|
||||||
public byte Ending;
|
public byte Ending = ending;
|
||||||
public byte PriorityIndex;
|
public byte PriorityIndex = priorityIndex;
|
||||||
public int Index;
|
public int Index = 0;
|
||||||
|
|
||||||
public HeuristicGroupBSequenceState(byte ending, byte priorityIndex)
|
|
||||||
{
|
|
||||||
Ending = ending;
|
|
||||||
PriorityIndex = priorityIndex;
|
|
||||||
Index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryPeek(ulong maxDivisorSquare, out ulong divisor)
|
public bool TryPeek(ulong maxDivisorSquare, out ulong divisor)
|
||||||
{
|
{
|
||||||
ReadOnlySpan<uint> divisors = GetGroupBDivisors(Ending);
|
ReadOnlySpan<uint> divisors = GetGroupBDivisors(Ending);
|
||||||
ReadOnlySpan<ulong> squares = GetGroupBDivisorSquares(Ending);
|
ReadOnlySpan<ulong> squares = GetGroupBDivisorSquares(Ending);
|
||||||
int index = Index;
|
int index = Index;
|
||||||
if ((uint)index >= (uint)divisors.Length)
|
if (index >= divisors.Length)
|
||||||
{
|
{
|
||||||
divisor = 0UL;
|
divisor = 0UL;
|
||||||
return false;
|
return false;
|
||||||
@@ -642,7 +624,7 @@ public sealed class HeuristicPrimeTester
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
divisor = (ulong)divisors[index];
|
divisor = divisors[index];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -731,11 +713,11 @@ public sealed class HeuristicPrimeTester
|
|||||||
residueStepper.Advance();
|
residueStepper.Advance();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ulong ProcessedCount => processedCount;
|
public readonly ulong ProcessedCount => processedCount;
|
||||||
|
|
||||||
public ulong LastDivisor => lastDivisor;
|
public readonly ulong LastDivisor => lastDivisor;
|
||||||
|
|
||||||
public bool Exhausted => !active;
|
public readonly bool Exhausted => !active;
|
||||||
|
|
||||||
private static HeuristicDivisorCandidate CreateCandidate(ulong value)
|
private static HeuristicDivisorCandidate CreateCandidate(ulong value)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ public sealed class PrimeTester
|
|||||||
// ResidueComputationBenchmarks so divisor-cycle metadata can short-circuit the test
|
// ResidueComputationBenchmarks so divisor-cycle metadata can short-circuit the test
|
||||||
// instead of recomputing binary GCD for every candidate.
|
// instead of recomputing binary GCD for every candidate.
|
||||||
ulong m = (ulong)BitOperations.Log2(n);
|
ulong m = (ulong)BitOperations.Log2(n);
|
||||||
return BinaryGcd(n, m) != 1UL;
|
return n.BinaryGcd(m) != 1UL;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void SharesFactorWithMaxExponentBatch(ReadOnlySpan<ulong> values, Span<byte> results)
|
internal static void SharesFactorWithMaxExponentBatch(ReadOnlySpan<ulong> values, Span<byte> results)
|
||||||
@@ -298,39 +298,4 @@ public sealed class PrimeTester
|
|||||||
PrimeOrderCalculatorAccelerator.Return(gpu);
|
PrimeOrderCalculatorAccelerator.Return(gpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static ulong BinaryGcd(ulong u, ulong v)
|
|
||||||
{
|
|
||||||
// TODO: Swap this handwritten binary GCD for the optimized helper measured in
|
|
||||||
// GpuUInt128BinaryGcdBenchmarks so CPU callers share the faster subtract-less
|
|
||||||
// ladder once the common implementation is promoted into PerfectNumbers.Core.
|
|
||||||
// You have an example in the benchmarks and you already implemented it in
|
|
||||||
// GpuUInt128, iirc.
|
|
||||||
if (u == 0UL)
|
|
||||||
{
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (v == 0UL)
|
|
||||||
{
|
|
||||||
return u;
|
|
||||||
}
|
|
||||||
|
|
||||||
int shift = BitOperations.TrailingZeroCount(u | v);
|
|
||||||
u >>= BitOperations.TrailingZeroCount(u);
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
v >>= BitOperations.TrailingZeroCount(v);
|
|
||||||
if (u > v)
|
|
||||||
{
|
|
||||||
(u, v) = (v, u);
|
|
||||||
}
|
|
||||||
|
|
||||||
v -= u;
|
|
||||||
}
|
|
||||||
while (v != 0UL);
|
|
||||||
|
|
||||||
return u << shift;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user