I want to control the output of every random value with a seed. When I code in Houdini’s VEX language I use rand(seed)
to get a value between 0-1 consistently. Here in Unity C# I understood that with Random.value
I also get a value between 0-1 and with Random.InitState()
I set the seed. When I run Random.value
again it results in a different value. What changed the seed?
public float result1;
public float result2;
void Start()
{
Random.InitState(1);
result1 = Random.value; // 0.9996847
result2 = Random.value; // 0.7742628 - Why is this different? What is the seed?
Debug.Log("Result 1: " + result1);
Debug.Log("Result 2: " + result2);
}
Why do I have to set Random.InitState(1);
again like this?
public float result1;
public float result2;
void Start()
{
Random.InitState(1);
result1 = Random.value; // 0.9996847
Random.InitState(1);
result2 = Random.value; // 0.9996847
Debug.Log("Result 1: " + result1);
Debug.Log("Result 2: " + result2);
}
A pseudo random number generator is an algorithm which produces a pseudo random number sequence. It will always produce the exact same sequence. However you can seed such a generator to start at a “certain” point in that sequence. When you call InitState you do exactly that. You initialize the internal state of the PRNG based on the given seed value.
Your confusion might come from the fact that Random.value is not a field / variable but it’s a property. So reading the value property will advance the PRNG to get the next number in the sequence. It should be pretty intuitive that reading “Random.value” to give you a “random value”
Note that a seed value works just like a real (plant) seed. It just sets the initial state and the system then grows based on that initial seed.
Unity’s Random class “currently” uses the XorShift 128 algorithm. How Unity actually uses the provided seed to actually “seed” the PRNG I don’t know. However the state of the xorshift must not be all 0 since it relies solely on permutation of the internal state. Since the seed you can provide is just a single 32 bit integer when you call InitState they might simply use your provided value as one of the 4 internal state integers and set the others to fix predefined values.
The exact implementation Unity uses we don’t know since it’s implemented inside the native part of the Unity engine. Unity already changed it’s algorithm once in the past. (AFAIK they used a Mersenne twister in the past and then switched to xorshift128). If you want to ensure to get the same behaviour, even in 10 years from now, you might want to use your own implementation. I’ve once implemented the xorshift 64 variant. Of course larger internal states “usually” result in higher quality random numbers and longer periods. Every PRNG has a certain period. After that amount of numbers the numbers just repeat. This period can’t be larger than the numbers of bits in the internal state (but can be way lower depending on the algorithm). According to the wiki article the xorshift128 does actually have the highest period of 2^128-1 which is about 3.4 * 10^38 numbers. Just in case you can’t read scientific notation that’s a 3 followed by 38 digits. So in any real life applications they will never repeat ^^.
Note that when you use a specific seed for every number you want to generate, that’s not “random” at all. It’s just one step in a fix computation. Just like if you multiply the value by 42 for example. So given the value 1 your get 42 as a result. For a value of 2 you get a value of 84 and so on. That’s exactly what would happen when you set the state to a fix seed and do a single iteration.
So I’m not sure what you want to do here. Using a fix seed every time you query a number doesn’t seem to make much sense.