A Tip When Using Math.random in AS3

So I found out something interesting when using Math.random in AS3: when you use Math.round, which is basically the best, most unbiased way to try to get whole numbers, the minimum and maximum outcomes will actually have LESS of a chance than every other number. So for instance, if you were trying to generate a number from 1-10, 2-9 would have a higher chance (11.25% each) of getting generated than 1 and 10 (5.62% each) instead of all of them actually being at 10%.

Now why is this? Well, since the minimum number is 1, the only possible way to get a 1 is to get anywhere from 1 to 1.5, while getting another random number like, say, 6, you can get anywhere from 5.5 to 6.5, which, as you can see, is double the leeway of getting a 1 (and the same exact thing obviously applies to 10, since you have to get a number anywhere from 9.5 to 10).

So this is just something to keep in mind when using the RNG in AS3. I did find a workaround you can use to get a true, unbiased percent for whatever you’re doing, however: if you were trying to get a number from 1 to 10, code it as 0 to 11 instead. 0 and 11 will have a lower chance of getting picked than the other numbers, but if they DO get picked, you can make the randomizer run again. So for example:

var rng = Math.round(Math.random() * 11);
if (rng == 0)
{
rng = Math.round(Math.random() * 11);
}
if (rng == 11)
{
rng = Math.round(Math.random() * 11);
}

This will give you a randomizer that generates any number from 1-10 at an actual 10% each.

If someone knows of a way to do this without the workaround, please let me know. Otherwise, you can just do this. Hope you learned something, and thanks for reading.

Just use Math.random() * (max + 1) | 0 aka Math.floor(Math.random() * (max + 1))

Or for less predictable randomness:

import flash.crypto.generateRandomBytes

const
	min:uint = 0,
	max:uint = 10

for(var i:int = 0; i < 4000; i++){
	var bytes:ByteArray = generateRandomBytes(4)
	trace(((bytes.readUnsignedInt() / uint.MAX_VALUE) * (max - min + 1) | 0) + min)
}
1 Like

I don’t quite understand what the (max + 1) means, and doesn’t Math.floor make it so it rounds down? Please explain, thank you.

Math.random will give you 0.0 through 0.9999999999. Multiplying it by max, if you set max to 10, will give you 0.0 through 9.99999. Multiplying by max + 1 will get you 0.0 through 10.9999. Flooring the result will get you 0 through 10 as possible results.

See also:

https://www.kirupa.com/developer/actionscript/tricks/random.htm
https://www.kirupa.com/flash/advanced_random_numbers_as3.htm


1 Like

Ah, this works very well, thank you, that’s exactly what I was looking to do.

1 Like

This was really neat.(from mozilla in @krilnon’s link)

// Returns a random integer between min (included) and max (included)
// Using Math.round() will give you a non-uniform distribution!
function getRandomIntInclusive(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

It’s also basically what I posted 3 posts above the link you’re talking about. :trout: But yeah; it’s neat!

I know, I know. But there was an extra +min that had me :blush:

I never seen this | 0. What does that mean?

| converts numbers into integers (and floors them in the process). It’s also the bitwise or operator, but since it’s always paired with 0 in our context, it’s basically just serving as a replacement of Math.floor.

1 Like

Show off…

Hahaha!

I have to apologize, I really didn’t see your +min Krilnon. :slightly_smiling: