# Random.Range int max is no longer exclusive

I am using Unity 2021.3.7f1, and according to the documentation for 2021.3, the max value of Random.Range int is exclusive.

(the beginning of the highlighted part also has a typo)

But I just did some random object generation with that in mind (I wanted maximum of 2 to spawn), and looky here.

3 meat gameobjects.
All I’m doing is putting the random number into a for loop checking “i < meatAmount” so for 3 meats it’d go “0, 1, 2” and then stop loop.

1 Like

Well I feel stupid… Could a moderator please delete this thread? I don’t really know how to seek them out to DM them.
I honestly feel so embarrassed right now I don’t even wanna say why.

2 Likes

Int or Float

I’m just really dragging it out for fun…

2 Likes

Lol, it’s okay. Range(float, float) was always inclusive. Range(int, int) was always exclusive.

The reason for that is because of how random values are actually generated.
I made a random RNG based on a permuted congruential generator (PCG) and basically you generate wild hashes that fill all the available value space of an integer. It’s a binary noise, so to speak, and the issue is when you want to extract something meaningful with it, you then want to scale this noise from the range of 0-2^31 to a ranged mapping. If that range is integral, there is neat integer division trick where you compute a division remainder instead, and thus clamp it to the range (where the modulus becomes out of reach, i.e. exclusive), but if the range is a floating point, such as Random.value, then you have to divide the whole sausage with int.MaxValue (2^31), and so you’d have to have a number that is exactly 2^31 to return exactly 1.0f which happens in 1/2^31 cases. So the truth is, while the floating point range is inclusive, because you typically get well-distributed values so near to 1.0f (when they’re near), they’re almost as good as 1.0f itself. Range(float, float) just extrapolates from Random.value, or better said “interpolates”.

Random.value => _random_int / (float)int.MaxValue;
Range(float min, float max) => min + Random.Value * (max - min);
Range(int min, int max) => min + _random_int % (max - min);

This is a naive approach ofc, there are techniques and techniques to improve on the integral distribution based on prime numbers.

2 Likes

Actually using the modulo has a uniform distribution with the exception on the very last section unless your range is a power of two so the whole range divides without rest. The simplest solution when you need a fair random roll is to simply re-roll a new number if it falls in the last incomplete set.

Just as an example if the range is 7, the highest signed integer value mod 7 is 1. So the last incomplete set only contains the number 0 and 1. So technically those have a slightly higher probability. Though with such a small range the difference would not really matter as there are over 300 million complete sets (0 - 6) and just one incomplete. However at larger ranges it becomes more of a problem. So by simply exluding the last incomplete set you get a perfect uniform distribution.

2 Likes

@Bunny83 something like that yes, though when you exclude a set, you lose a chunk of entropy (of course for large intervals). I forgot how exactly I solved this, it was per recommendation of someone smarter than me, armed with a suite of tools for random distribution analysis. I remember only spending a lot of time Monte-Carloing, making sure I didn’t mess something up. but it was several years ago, I might do it again. if I do, I’ll remember to post what the solution was exactly.

I used this for all my TRS-80 Model 100 games back in 1984.

If you just called it and graphed the output it wasn’t great.

But if you called it a lot from all over your program, it actually did fantastically well, and I never “felt” like my games ever played twice or were predictable in any way.

``````; easy cheesy random numbers on an 8085 CPU on the TRS-80 Model 100:
; uses contents of A and whatever HL happens to be pointing to at time of call
RND:
PUSH    HL         ; preserve
LD    HL,RR        ; first byte of random state
LD    (HL),A
INC    HL            ; advance to next byte of random state
LD    (HL),A
INC    HL            ; advance to next byte of random state
LD    (HL),A
POP    HL
RET

RR    DS    3            ; 3 bytes of random state
``````

You can play it in any of the games prefixed with “VV” in my KurtMaster2D app.

Apple iTunes: ‎KurtMaster2D on the App Store

OH YEAH! I forgot I opened sourced all this code years ago and you can see it all here, including built binaries of the above games to run on your TRS-80 Model 100.

https://bitchin100.com/m100-oss/archive.html

4 Likes

Wow I wish anything from my 80’s survived. My life is like a Winamp visualization, you know the shader where the buffer is constantly blurred and fading away.

2 Likes

Same, all my old stuff… probably gone </3

1 Like