Align bit transform comments with original implementation
This commit is contained in:
1 parent
7f468de485
commit
56c8e84c19
8 files changed
+417
-370
No files matched your search
@@ -0,0 +1,79 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using EvenPerfectBitScanner.Candidates;
|
||||
using Open.Numeric.Primes;
|
||||
|
||||
namespace EvenPerfectBitScanner.Candidates.Transforms;
|
||||
|
||||
internal static class CandidateAddPrimesTransform
|
||||
{
|
||||
private static readonly Optimized PrimeIterator = new();
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static ulong Transform(ulong value, ref ulong remainder, ref bool limitReached)
|
||||
{
|
||||
ulong originalRemainder = remainder;
|
||||
ulong addRemainder = remainder;
|
||||
ulong candidate = value;
|
||||
ulong primeCandidate = value;
|
||||
bool advanceAdd = true;
|
||||
bool advancePrime = true;
|
||||
ulong diff;
|
||||
ulong nextPrime;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (advanceAdd)
|
||||
{
|
||||
diff = addRemainder.GetNextAddDiff();
|
||||
if (candidate > ulong.MaxValue - diff)
|
||||
{
|
||||
Volatile.Write(ref limitReached, true);
|
||||
remainder = originalRemainder;
|
||||
return candidate;
|
||||
}
|
||||
|
||||
candidate += diff;
|
||||
addRemainder += diff;
|
||||
// Skip the Mod6 lookup: benchmarked `%` stays ahead for these prime increments.
|
||||
// benchmarked fastest remainder updates instead of looping subtraction.
|
||||
while (addRemainder >= 6UL)
|
||||
{
|
||||
addRemainder -= 6UL;
|
||||
}
|
||||
}
|
||||
|
||||
if (advancePrime)
|
||||
{
|
||||
try
|
||||
{
|
||||
nextPrime = PrimeIterator.Next(in primeCandidate);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
Volatile.Write(ref limitReached, true);
|
||||
remainder = originalRemainder;
|
||||
return value;
|
||||
}
|
||||
|
||||
if (nextPrime <= primeCandidate)
|
||||
{
|
||||
Volatile.Write(ref limitReached, true);
|
||||
remainder = originalRemainder;
|
||||
return value;
|
||||
}
|
||||
|
||||
primeCandidate = nextPrime;
|
||||
}
|
||||
|
||||
if (candidate == primeCandidate)
|
||||
{
|
||||
remainder = addRemainder;
|
||||
return candidate;
|
||||
}
|
||||
|
||||
advanceAdd = candidate < primeCandidate;
|
||||
advancePrime = candidate > primeCandidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using EvenPerfectBitScanner.Candidates;
|
||||
|
||||
namespace EvenPerfectBitScanner.Candidates.Transforms;
|
||||
|
||||
internal static class CandidateAddTransform
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static ulong Transform(ulong value, ref ulong remainder, ref bool limitReached)
|
||||
{
|
||||
ulong next = value;
|
||||
ulong diff = remainder.GetNextAddDiff();
|
||||
|
||||
if (next > ulong.MaxValue - diff)
|
||||
{
|
||||
Volatile.Write(ref limitReached, true);
|
||||
return next;
|
||||
}
|
||||
|
||||
remainder += diff;
|
||||
// Retain direct modulo because the Mod6 helper underperforms on 64-bit operands.
|
||||
while (remainder >= 6UL)
|
||||
{
|
||||
remainder -= 6UL;
|
||||
}
|
||||
|
||||
return next + diff;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace EvenPerfectBitScanner.Candidates.Transforms;
|
||||
|
||||
internal static class CandidateBitTransform
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static ulong Transform(ulong value, ref ulong remainder, ref bool limitReached)
|
||||
{
|
||||
ulong original = value;
|
||||
if (value > (ulong.MaxValue >> 1))
|
||||
{
|
||||
Volatile.Write(ref limitReached, true);
|
||||
return value;
|
||||
}
|
||||
|
||||
ulong next = (value << 1) | 1UL;
|
||||
remainder = (remainder << 1) + 1UL;
|
||||
// Mod6 lookup loses to `%` in the benches; stick with subtraction + modulo for correctness and speed.
|
||||
while (remainder >= 6UL)
|
||||
{
|
||||
remainder -= 6UL;
|
||||
}
|
||||
|
||||
value = remainder switch
|
||||
{
|
||||
0UL => 1UL,
|
||||
1UL => 0UL,
|
||||
2UL => 5UL,
|
||||
3UL => 4UL,
|
||||
4UL => 3UL,
|
||||
_ => 2UL,
|
||||
}; // 'value' now holds diff
|
||||
|
||||
if (next > ulong.MaxValue - value)
|
||||
{
|
||||
Volatile.Write(ref limitReached, true);
|
||||
return original;
|
||||
}
|
||||
|
||||
remainder += value;
|
||||
// `% 6` remains faster per Mod6ComparisonBenchmarks; keep this modulo fold and continue using subtraction.
|
||||
while (remainder >= 6UL)
|
||||
{
|
||||
remainder -= 6UL;
|
||||
}
|
||||
|
||||
return next + value;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user