Skip to content

Commit

Permalink
Even faster modulo computation: remove one of the three multiplicatio…
Browse files Browse the repository at this point in the history
…ns. (#406)
  • Loading branch information
AntonLapounov authored and jkotas committed Jan 22, 2020
1 parent 4dbc6f1 commit ea9bfd2
Showing 1 changed file with 8 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -90,21 +90,24 @@ public static int ExpandPrime(int oldSize)
}

#if BIT64
// Returns approximate reciprocal of the divisor: ceil(2**64 / divisor)
public static ulong GetFastModMultiplier(uint divisor)
=> ulong.MaxValue / divisor + 1;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint FastMod(uint value, uint divisor, ulong multiplier)
{
// Using fastmod from Daniel Lemire https://lemire.me/blog/2019/02/08/faster-remainders-when-the-divisor-is-a-constant-beating-compilers-and-libdivide/
// We use modified Daniel Lemire's fastmod algorithm (https://github.com/dotnet/runtime/pull/406),
// which allows to avoid the long multiplication if the divisor is less than 2**31.
Debug.Assert(divisor <= int.MaxValue);

ulong lowbits = multiplier * value;
// 64bit * 64bit => 128bit isn't currently supported by Math https://github.com/dotnet/corefx/issues/41822
// otherwise we'd want this to be (uint)Math.MultiplyHigh(lowbits, divisor)
uint high = (uint)((((ulong)(uint)lowbits * divisor >> 32) + (lowbits >> 32) * divisor) >> 32);
// otherwise we'd want this to be (uint)Math.BigMul(lowbits, divisor, out _)
uint highbits = (uint)((((lowbits >> 32) + 1) * divisor) >> 32);

Debug.Assert(high == value % divisor);
return high;
Debug.Assert(highbits == value % divisor);
return highbits;
}
#endif
}
Expand Down

0 comments on commit ea9bfd2

Please sign in to comment.