Reputation: 5006
I'm working on my optimized XorShift32
pseudo-random number generator to be used for unit tests. It's significantly faster than System.Random, with unsafe
optimizations it's way faster. Plus I added server handy methods to make my unit testing easier. However I have a problem with it correctness since the overflow when using ranges close to Int32.MinValue
and Int32.MaxValue
.
Here's the method (I know it's incorrect):
/// <summary>
/// Returns a random integer that is within a specified range.
/// </summary>
/// <param name="min">The inclusive lower bound of the random number returned.</param>
/// <param name="max">The exclusive upper bound of the random number returned. maxValue must be greater than or equal to minValue.</param>
/// <returns>A 32-bit signed integer greater than or equal to minValue and less than maxValue; that is, the range of return values includes minValue but not maxValue. If minValue equals maxValue, minValue is returned.</returns>
public int Next(int min, int max) {
if (min == max) return min;
Seed ^= Seed << 13;
Seed ^= Seed >> 17;
Seed ^= Seed << 5;
if (min == int.MinValue && max == int.MaxValue) return unchecked((int)Seed);
return min + (int)(Seed / Max * (max - min));
}
When Math.Abs(max - min) < Int32.MaxValue
it returns correct numbers, but otherwise the numbers overflow. First, the condition stated above seems to make sense for a human, but not necessarily for the compiler or IL. Anything except Int32.MaxValue
is less than Int32.MaxValue
so using that in code is pointless. Then again I could cast max and min to Int64
, then make the calculations, but the issue is it would defeat all optimizations gain here.
Any ideas how to limit the output range FAST?
Let's consider the test case: var x = R.Next(-1, Int32.MaxValue)
. This code will fail miserably on this. How to make it correct without hitting the performance too much?
BTW, I know there's no practical reason of making such PRNG, I'm doing it solely for learning purpose.
Upvotes: 0
Views: 577
Reputation: 111950
Take a look at what Microsoft did for Random.Next(min, max)
long range = (long)max-min;
They used long
:-)
and then
return min + (int)(Seed / Max * range);
Upvotes: 2