Search Unity

Discussion Random.Range int max is no longer exclusive

Discussion in 'Scripting' started by Josiah_Ironclad, Sep 15, 2022.

  1. Josiah_Ironclad

    Josiah_Ironclad

    Joined:
    Sep 24, 2019
    Posts:
    156
    I am using Unity 2021.3.7f1, and according to the documentation for 2021.3, the max value of Random.Range int is exclusive. upload_2022-9-15_1-17-55.png
    (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.
     
    Last edited: Sep 15, 2022
    hippocoder likes this.
  2. Josiah_Ironclad

    Josiah_Ironclad

    Joined:
    Sep 24, 2019
    Posts:
    156
    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.
     
    Last edited: Sep 15, 2022
    orionsyndrome and hippocoder like this.
  3. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Int or Float :D

    I'm just really dragging it out for fun...
     
  4. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,113
    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.
     
    Last edited: Sep 15, 2022
    Josiah_Ironclad and hippocoder like this.
  5. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    4,005
    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.
     
    hippocoder and orionsyndrome like this.
  6. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,113
    @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.
     
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    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.

    Code (csharp):
    1. ; easy cheesy random numbers on an 8085 CPU on the TRS-80 Model 100:
    2. ; uses contents of A and whatever HL happens to be pointing to at time of call
    3. RND:
    4.     PUSH    HL         ; preserve
    5.     ADC    (HL)
    6.     LD    HL,RR        ; first byte of random state
    7.     ADC    (HL)
    8.     LD    (HL),A
    9.     INC    HL            ; advance to next byte of random state
    10.     ADD    (HL)
    11.     LD    (HL),A
    12.     INC    HL            ; advance to next byte of random state
    13.     ADC    (HL)
    14.     LD    (HL),A
    15.     POP    HL
    16.     RET
    17.  
    18. 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: https://itunes.apple.com/us/app/kurtmaster2d/id1015692678
    Google Play (including TV): https://play.google.com/store/apps/details?id=com.plbm.plbm1

    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
     
    Last edited: Sep 15, 2022
  8. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,113
    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.
     
    Anthiese and Kurt-Dekker like this.
  9. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Same, all my old stuff... probably gone </3
     
    Kurt-Dekker likes this.