mathnet / mathnet-numerics

Math.NET Numerics
http://numerics.mathdotnet.com
MIT License
3.44k stars 891 forks source link

Mersenne twister GetInt32s exception #508

Open karlra opened 6 years ago

karlra commented 6 years ago

The sixth overload of MathNet.Numerics.Random.MersenneTwister.Default.NextInt32s has the signature:

MathNet.Numerics.Random.RandomSource.NextInt32s(Int32[] values, Int32 minInclusive, Int32 maxExclusive)

The method says it should returned signed integers, so one would expect it to work in the range int.MinValue to int.MaxValue. Calling it like this works:

int[] buffer = new int[10];
MathNet.Numerics.Random.MersenneTwister.Default.NextInt32s(buffer, 0, 10);

Calling it like this works too:

int[] buffer = new int[10];
MathNet.Numerics.Random.MersenneTwister.Default.NextInt32s(buffer, -1, int.MaxValue - 1);

However, increasing the range by 1 by setting the second parameter to -2 instead gives the exception

System.ArgumentOutOfRangeException occurred
  HResult=0x80131502
  Message=Specified argument was out of the range of valid values.
  Source=<Cannot evaluate the exception source>
  StackTrace:
   at MathNet.Numerics.Euclid.PowerOfTwo(Int32 exponent)
   at MathNet.Numerics.Random.RandomSource.DoSampleInteger(Int32 maxExclusive)
   at MathNet.Numerics.Random.RandomSource.DoSampleInteger(Int32 minInclusive, Int32 maxExclusive)
   at MathNet.Numerics.Random.RandomSource.NextInt32s(Int32[] values, Int32 minInclusive, Int32 maxExclusive)

It seems that whenever you make the range of integers larger than abs(int.MinValue) then you get the above exception.

I'm pretty new to this library, am I misunderstanding something? Is the range of possible values actually only half of the int range? I'm using this in .net core 2.0, could that have anything to do with it? I haven't run into any other issues like this and everything seems to work otherwise.

karlra commented 6 years ago

I see the discussion in the manual about system generators being in the range [0, int.MaxValue] and that you could use NextFullRangeInt32(), but that has no range parameter. So it is not possible to generate an int in a range larger than half the int range, but within a specific range?