Random.Range doesn't look random?

Hi all,

I’ve been testing the random function in Unity and so far, it looks like it isn’t random (or it’s just a pure bad luck).

Simply; I initialize the state of the random function once (by using the InitState function) and give the current milliseconds of the PC as the seed. When the scene loads, the game waits a bit to spawn 2 game objects. After the objects are spawned, I generate 2 random colors and change their colors. I move the objects forward a bit and then destroy them. This process repeats in the game.

Here’s the results:

  • When the game starts for first time, 2 objects are spawned at the same time even though I set their spawn times with Random.Range function. It happens always, every time the game starts for first time. Afterwards, everything is random. But for the first time, the random function always return same float number in the same frame, which is 0.5 in my case.

  • The colors are not random usually. For example, let’s say the first object’s color is set to red. When the object is destroyed and spawned again, the random function returns red color again. After repeating the same color 2-3 times, it generates another color. It may sound like a bad luck, but I generate 3 random numbers to generate a random color, which means the function returns the same pattern 2-3 times.

Here’s the pseudo version of my code:

    public static Color GetRandomColor(float minValue, float maxValue)
    {
        minValue /= 255.0f;
        maxValue /= 255.0f;

        return new Color(Random.Range(minValue, maxValue), Random.Range(minValue, maxValue), Random.Range(minValue, maxValue));
    }

    float object1SpawnTime;
    float object2SpawnTime;

    GameObject object1 = null;
    GameObject object2 = null;

    private void Start()
    {
        object1SpawnTime = Random.Range(0.5f, 3.5f);
        object2SpawnTime = Random.Range(0.5f, 3.5f);
    }

    private void Update()
    {
        object1SpawnTime -= Time.deltaTime;
        object2SpawnTime -= Time.deltaTime;

        if(object1 == null && object1SpawnTime <= 0.0f)
        {
            //... Spawn the object and set the 'object1' variable

            Color color = GetRandomColor(100.0f, 200.0f);

            //... Set the object's color
        }
        if (object2 == null && object2SpawnTime <= 0.0f)
        {
            //... Spawn the object and set the 'object2' variable

            Color color = GetRandomColor(100.0f, 200.0f);

            //... Set the object's color
        }

        //... Move the objects

        if (object1.transform.position.x > 2.0f)
        {
            Destroy(object1);
            object1 = null;

            object1SpawnTime = Random.Range(0.5f, 3.5f);
        }
        if (object2.transform.position.x > 2.0f)
        {
            Destroy(object2);
            object2 = null;

            object2SpawnTime = Random.Range(0.5f, 3.5f);
        }
    }

Why does this happen? Is this because I test the game in the editor? Is this because changing the scene does something to the seed? I don’t understand.

It can be a lot of things. For one, your eye is only half as sensitive to changes in red as it is in green, and only one sixth (1/6th!) as sensitive to changes in blue. Therefore perception is always a poor way to measure randomness.

It also could be a bug in your code, but that’s hard to prove/disprove in most cases.

There are standard measures you can do to any source of random numbers to evaluate their randomness. This is used in many industries such as stochastic modeling, gambling, financial modeling, etc.

That said, Unity’s random is just a black box to us. I don’t think (haven’t checked in a while) Unity gives you any representation or insight into its mechanism, reliability, cycle length, etc. Furthermore, if you measured it and it was bad, there’s not much you can do with it. Unity is closed source.

Instead, just download your favorite open source random number code and use that instead. There’s plenty out there, along with tons of scholarly research on them. But I would guess given the subjective nature of your complaint, you won’t “feel” they are any more random than what Unity does.

Are you CERTAIN that it’s the random function actually returning these values? It’s possible you may have some values getting cached, if you for example are using an object pooling system or are instantiating these objects as clones of each other, they might be retaining some old values.

Add a Debug.Log to GetRandomColor and make sure that you get a log every single time a new one of these is spawned - I’m guessing it’s not getting called every time.

1 Like

Your post describing some things as random and others as non-random doesn’t make it clear to me that you necessarily understand what to look for when making that determination.

Hypothetically, if you messed up the code for initializing the random number generator such that it always gets the same initial value, then everything after that point would be the same every time you run. (For example, this might happen if you used the time since the app started instead of the system time, since the time since the app started is always going to be zero when the app first starts.)

NOTE: I’m pretty sure UnityEngine.Random is already automatically seeded based on the time, so unless you are doing something tricky, there’s probably no benefit to you initializing it in your own code.

This kind of error wouldn’t make it any more likely that you first 2 objects both spawn at the same time as each other, but if you coincidentally happened to get a seed that made them both spawn at the same time, you would continue to get that every time you clicked “run”.

More generally, it won’t make you any more likely to get duplicated numbers within a single test, but if you click “stop” and then “play” again, you’ll get the same sequence of numbers as last time. For example your first run might output 17, 21, 49, 5, 52, and then the next time you ran you’d get the same sequence of numbers 17, 21, 49, 5, 52.

Now…if the spawn times for your objects after the first batch are different each run–NOT that the two objects fall out of sync in a given test, but that the timing changes when you click “stop” and then click “play” again–then that suggests to me that this isn’t a problem with the random number generator, because if the random outputs are fixed, then all of them should be fixed until you do something to alter the settings.

So my guess is that your problem has nothing to do with the random numbers per se, but with the way that you structured your code. For example, one possibility is that something is making your very first frame take a long time to render, which then means in the second frame Time.deltaTime would have a pretty big value, and if it’s bigger than your random range then your first objects will always spawn in your second frame no matter what random times you assigned them.

You might add some Debug.Log lines to print out the values of object1SpawnTime, object2SpawnTime, and Time.deltaTime the first time that Update gets called.

However, it would be kind of surprising if the Unity editor really takes >3.5 seconds to render the first frame of your game after you click “play”.

Actually Unity uses Xorshift128 which was mentioned by andeeeee which is / was a Unity developer. The state gives us a cycle length of 128 bit.

Thanks for pointing that out @Bunny83 … I’m unfamiliar but if it’s just an LFSR and it’s 128-bits, it’s gonna be plenty random enough for game use!!

A 128-bit state gives you an upper bound of 2^128 for the cycle length. That’s what you hope you get. What you actually get might well be less than that.

1 Like

Completely agree with StarManta, investigate and debug the actual values, at the moment you’re just making assumptions about whether it’s working or not. Rather than doing all this complicated stuff just check if it’s working first then fix it, seems like too many people in the thread are offering solutions when we don’t 100% know what’s going on yet.

It’s worth pointing out though, I’ve used Random.Range myself and I even use it for things like spawning the player in and sometimes I can get it on the same ‘random’ number 3 in a row. This is because the number truly is random and that means as you think OP it can just be down to luck if you get the same results.

While this is generally true, the Xorshift 128 has a period of 2^128-1. Actually most PRNG’s based on LFSR’s are implemented with maximum length. If not in most cases you could reduce the bit count in the state. Note that while Xorshif has a state of 128 bits, it only generates 32 bit values. This actually improves the quality since we can get duplicates in the 32 bit range. Note that with PRNG’s there is nothing to hope for. The behaviour is 100% deterministic. If you have a period that is smaller than the max length, it’s just a bad implementation, for whatever reason.

It is not true that “Xorshift” has a period of 2^N-1. “Xorshift” is not a single PRNG, it’s a family of PRNGs (differing in what exact bitshifts they use), and different generators within that family have different periods. So until you specify exactly which one out of that family of algorithms you are talking about, there is conversational uncertainty over which bitshifts you are using and how long a period they achieve, and I can “hope” that you picked one of the good ones.

From the same Wikipedia page you linked, “Like all LFSRs, the parameters have to be chosen very carefully in order to achieve a long period.”

And of course, no random discussion is complete without this:

1 Like

I suggest doing a Debug.Log() on your object1 and object2 right after they’re given a value in Start(). Debug.Log the values of your Colors each time they’re created. Verify that the numbers themselves actually vary from run to run. That will help determine the next step.

i was having a similar problem as the OP, i had a function that got a random number between 1 and 10 if it was 10 it would keep getting a new random number until it was not longer 10 and it would keep adding that number (so, if it rolls a 10 it rolls again, if it rolls a 10 again it adds that 10 to the previous and rolls again, continuing til it’s not a 10) but it seems the algorithm random.range uses does not like it if you get a bunch of numbers in quick succession, that is it will be biased towards the last random number (in my case it meant if i rolled a 10 i was more likely to roll another 10 in my while loop, or to roll a number close to 10)

this is because unity uses the same seed every time, if you are getting them in rapid succession you may need to change the seed between rolls. in my case i just changed the rng to system.security.cryptography.RandomNumberGenerator, i made a simple function to handle it:

/// <summary>
/// Generates a random integer within a specified range using the 
/// System.Security.Cryptography.RandomNumberGenerator class.
/// </summary>
/// <param name="low">The minimum value for the random integer.(Inclusive)</param>
/// <param name="high">The maximum value for the random integer.(Exclusive)</param>
/// <returns>A random integer within the specified range.</returns>
static int GetRandomRange(int low, int high)
{
int rand;
using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
{
byte[ ] randomBytes = new byte[1];
rng.GetBytes(randomBytes);
rand = (int)(randomBytes[0] % (high - low)) + low;
}
return rand;
}

if you need a random number >255 you might need more bytes. but this seems to have eliminated my excessive double crits.

None of that is right. Unity uses a version of xorshift 128 and the “seed” does change after each roll. That’s the point of PRNGs. xorshift does not have a bias. Just like good random numbers it’s possible to get long streaks that locally may “seem” like it’s not “random” but that’s just gambler’s fallacy. It’s perfectly fine to get 20 times a 10 in a row. It’s quite unlikely but a good random number generator does allow it to happen.^

It doesn’t matter how fast or slow you’re rolling random numbers as a pseudo random number sequence is always the same for a given seed. If you want random numbers you shouldn’t touch the seed at all. Setting the seed would give you the same sequence every time.

Cryptorgraphic secure random number generators usually include much more details in the generation of the initial seed to make the reverse engineering / guessing of the seed much harder. Most PRNGs simply use the current time at the start of the application as seed. This is perfectly fine for rolling random numbers. It’s just not a good idea when it comes to security since when you can guess the start time, you can narrow down the possible seeds and the system becomes “brute-forceable”.

Humans are really bad at detecting randomness:

And then there’s pareidolia to further confuse humans viewing random data:

EDIT: and of course this one, which afflicts many gamblers;

2 Likes

Unless you are doing something tricky and unusual, the proper way to use a random number generator is to have one generator, seed it one time, and then never create another generator or another seed. You just keep asking for more random numbers, and it will keep giving you different ones. (This is why Unity provides you with a convenient static random-generator that is automatically seeded and can be called from anywhere.)

Your example code creates an entirely new generator every time you want a new random number! Don’t do this. This will cause your random numbers to be correlated unless you seed every generator with a new, uncorrelated seed. (And if you could do that, then you could just use the seeds directly AS your random numbers, so this would still be pointless).

2 Likes