I know that Object.GetHashCode can return different values for the same object (an identical string, for example) depending on the platform. I thus can't rely on this for a cross-platform simple hash.
But can I rely on System.Random? Will it produce the same results for a given seed regardless of whether or not I'm on Microsoft .NET / Mono / x86 / x64, etc.?
Random seeds are often generated from the state of the computer system (such as the time), a cryptographically secure pseudorandom number generator or from a hardware random number generator.
This is because given a starting value (===> the seed) they will always provide the same sequence of pseudo random results. A good generator will produce a sequence that can not be distinguished - in statistical terms - from a true random sequence (throw a true die, true coin, etc).
Seed function is used to save the state of a random function, so that it can generate same random numbers on multiple executions of the code on the same machine or on different machines (for a specific seed value).
A random seed is a starting point in generating random numbers. A random seed specifies the start point when a computer generates a random number sequence. This can be any number, but it usually comes from seconds on a computer system's clock (Henkemans & Lee, 2001).
As Jeremy mentioned in his answer the documentation states that the number generator is not guaranteed consistent across .NET versions.
However, the documentation also tells you how to implement your algorithm too.
You can implement your own random number generator by inheriting from the Random class and supplying your random number generation algorithm. To supply your own algorithm, you must override the
Sample
method, which implements the random number generation algorithm. You should also override theNext()
,Next(Int32, Int32)
, andNextBytes
methods to ensure that they call your overridden Sample method. You don't have to override theNext(Int32)
andNextDouble
methods.
Using that we can make our own random class that uses a known fixed algorithm you can use. For example, we could go to the .Net source and implement the current random algorithm, this would allow us to use the ConsistantRandom
class and know for sure the algorithom won't change on us.
The following example is derived from the .NET Core 1.1.0 source.
using System;
namespace ConsoleApplication1
{
public class ConsistantRandom: Random
{
private const int MBIG = Int32.MaxValue;
private const int MSEED = 161803398;
private const int MZ = 0;
private int inext;
private int inextp;
private int[] SeedArray = new int[56];
public ConsistantRandom()
: this(Environment.TickCount)
{
}
public ConsistantRandom(int seed)
{
int ii;
int mj, mk;
int subtraction = (seed == Int32.MinValue) ? Int32.MaxValue : Math.Abs(seed);
mj = MSEED - subtraction;
SeedArray[55] = mj;
mk = 1;
for (int i = 1; i < 55; i++)
{
ii = (21 * i) % 55;
SeedArray[ii] = mk;
mk = mj - mk;
if (mk < 0) mk += MBIG;
mj = SeedArray[ii];
}
for (int k = 1; k < 5; k++)
{
for (int i = 1; i < 56; i++)
{
SeedArray[i] -= SeedArray[1 + (i + 30) % 55];
if (SeedArray[i] < 0) SeedArray[i] += MBIG;
}
}
inext = 0;
inextp = 21;
}
protected override double Sample()
{
return (InternalSample() * (1.0 / MBIG));
}
private int InternalSample()
{
int retVal;
int locINext = inext;
int locINextp = inextp;
if (++locINext >= 56) locINext = 1;
if (++locINextp >= 56) locINextp = 1;
retVal = SeedArray[locINext] - SeedArray[locINextp];
if (retVal == MBIG) retVal--;
if (retVal < 0) retVal += MBIG;
SeedArray[locINext] = retVal;
inext = locINext;
inextp = locINextp;
return retVal;
}
public override int Next()
{
return InternalSample();
}
private double GetSampleForLargeRange()
{
int result = InternalSample();
bool negative = (InternalSample() % 2 == 0) ? true : false;
if (negative)
{
result = -result;
}
double d = result;
d += (Int32.MaxValue - 1);
d /= 2 * (uint)Int32.MaxValue - 1;
return d;
}
public override int Next(int minValue, int maxValue)
{
if (minValue > maxValue)
{
throw new ArgumentOutOfRangeException("minValue");
}
long range = (long)maxValue - minValue;
if (range <= (long)Int32.MaxValue)
{
return ((int)(Sample() * range) + minValue);
}
else
{
return (int)((long)(GetSampleForLargeRange() * range) + minValue);
}
}
public override void NextBytes(byte[] buffer)
{
if (buffer == null) throw new ArgumentNullException("buffer");
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = (byte)(InternalSample() % (Byte.MaxValue + 1));
}
}
}
}
Because ConsistantRandom
derives from Random
you can use the class as a drop in replacement anywhere you had the type Random
before, you just need to replace Random rnd = new Random(yourSeed);
with Random rnd = new ConsistantRandom(yourSeed);
.
No, you can not rely on consistent values being generated across platforms or versions. From the .NET Framework docs for System.Random
(the less-detailed .NET Core docs don't address this):
The implementation of the random number generator in the Random class isn't guaranteed to remain the same across major versions of the .NET Framework. As a result, you shouldn't assume that the same seed will result in the same pseudo-random sequence in different versions of the .NET Framework.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With