Choosing Random Numbers Redux

Flash ActionScript 2.0

I goofed in my last post about choosing random numbers, so let’s take another look.  Big thanks to NSurveyor, by the way, for pointing it out!  In converting floats into integers last time, I used the static Math.round() method.  In the context of ensuring that a random choice is made with equal probability, there’s a subtle (but important!) distinction between rounding with Math.round() versus rounding with Math.ceil() or Math.floor().  I think a diagram will help. 

Everyone should get an equal piece of the pie

Math.round() does its rounding the way we learned back in grade school:  if the number in question is less than five, round down; if five or higher, round up.  My previous sample code was this:

Math.round(Math.random() * 9) + 1;

As NSurveyor points out in the previous post’s comments, the above is close, but not close enough.  The distribution is uneven, because 1s and 10s are less likely to be chosen over 2, 3, 4, …, 9.  Why?  Check it out.

Diagram illustrating distribution of Math.round() roumding

If the result of Math.random() * 9 happens to fall between 0 and 0.4, it would be rounded to 0.  That’s worth “one slice of pie.”  If it happens to fall between 0.5 and 0.9, it would be rounded to 1.  That, too, is one slice of pie.  So far, zero and one are tied.  With me?

If the number falls between 1 and 1.4, that also rounds to 1.  At this point, zero is behind, because one has two slices of pie.  The pattern continues:  a number between 1.5 and 1.9 rounds to 2, and so does 2 through 2.4.  All the middle numbers get two slices of pie, while the end numbers only get a single slice.

NSurveyor’s recommendation is this:

Math.floor(Math.random() * 10) + 1;

… which solves the issue.  In this case, numbers are always rounded down.  Everyone gets two slices of pie.

Diagram illustrating distribution of Math.floor() rounding

Likewise, his suggested change to my randomRange() sample goes like this:

function randomRange(min:Number, max:Number):Number {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

5 Responses to “Choosing Random Numbers Redux”

  1. NSurveyor Says:

    Glad I could help!

  2. Amy Says:

    Ok, so I sucked at math but I get the rounding bit. What I don’t understand is the purpose of separating it into 6 parts. Why not 0-.4, .5-1.4, 1.5-2.4, 2.5-3 where each, when rounded, equals a whole integer up to 3? Maybe this is your point and I’m daft. ;)

    I really appreciate your explaining this topic. It’s something I’ve always shied away from because I couldn’t see the use.

  3. David Stiller Says:

    Amy,

    I’m sure you’re not daft. ;) It may be that I confused matters by only going to up three in my diagrams, when my ActionScript code shows a range that goes higher. Six parts was just arbitrary, otherwise the image would have been wider.

    The first diagram is intended to show that the two end numbers — no matter how long the sequence — are only chosen half as often as the middle numbers. In my ActionScript, the return value of Math.random() * 9 might actually be, say, 9.7. When rounded with Math.round(), that would become 10. The return value might be 8.5, which would become 9. Might be 9.3, which would become 9. The number 9 has an unfair advantage over 10, in this case.

    Make sense? If not, let me know.

  4. NSurveyor Says:

    Of course it isn’t .4 but .49999999, and not .9 but .9999999999…though the above still illustrates the problem nicely.

    Another way to look at it:
    0.0<=x<0.5->Math.round(x)=0
    0.5<=x<1.5->Math.round(x)=1
    1.5<=x<2.5->Math.round(x)=2
    2.5<=x<3.5->Math.round(x)=3
    3.5<=x<4.5->Math.round(x)=4
    ….
    MAX-0.5<=x<MAX->Math.round(x)=MAX

    From this we see that the range for 0 and MAX is only 0.5, while the between numbers have a range of 1, and thus it is twice as likely to get a middle number than one of the ends.

  5. Amy Says:

    Cool, thanks to you both. This makes a lot more sense now. :)

Leave a Reply