dcsimg
A Flash Developer Resource Site

Results 1 to 12 of 12

Thread: bell curves

  1. #1
    Junior Member
    Join Date
    Dec 2003
    Location
    seattle
    Posts
    8

    bell curves

    I checked the previous posts on this subject and my head is swimming now!

    What I want to do is have a number generated randomly but conforming to the constrainsts of a bellcurve. For example, on a scale from 1 to 10 I would like to have more 5's returned than 1s and 10s.

    This math is just out of my league...

    Thanks

  2. #2
    Senior Member jbum's Avatar
    Join Date
    Feb 2004
    Location
    Los Angeles
    Posts
    2,920
    Here's one way to do it.

    This is off the top of my head. I'm simulating the actions of a bell-curve exhibit I saw at a science museum, some years ago.

    A ball was dropped from the top-center, and hit a row of pegs. The peg would cause the ball to go left or right with equal probability. Then it would hit another row of pegs, which would cause it to go left or right, and so on...

    This code is the algorithmic equivalent:

    Code:
    r = 5; // start in center
    
    // go left/right 5 times with equal probability
    for (var i = 0; i < 5; ++i) {
       r += random(2)? 1 : -1;
    }
    The maximum and minimum values for r are
    (5+1+1+1+1+1 and 5-1-1-1-1-1), or 10 - 0 which are both very unlikely. Most likely, r will be close to the center (5).

    Note that the range of r is 0-10 and not 1-10, as in your request.

    - Jim
    Last edited by jbum; 03-15-2004 at 05:15 AM.

  3. #3
    Junior Member
    Join Date
    Dec 2003
    Location
    seattle
    Posts
    8

    so close

    that method is the closest so far but it doesn't allow me to get a result of 1,3,5...any odd number on a range of say 1-10.

    Any other ideas???

  4. #4
    Senior Member jbum's Avatar
    Join Date
    Feb 2004
    Location
    Los Angeles
    Posts
    2,920
    NOTE: I correct an error in this post - 'r' was being miscalculated in the first example - jbum.

    Two questions:

    1) I'm not sure what you mean by odd numbers - are you saying you don't want 'r' to ever be an even number? Just the numbers 1,3,5,7,9 ? that's what the following example does, but I'm not sure that's what you mean...

    Code:
    // this will produce the values 1,3,5,7,9 with bell curve distribution
    
    var r = 2;
    for (var i = 0; i < 2; ++i) {
       r += random(2)? 1 : -1;
    }
    r = r*2 + 1;
    2) If you're trying to restrict the results to the range 1-10, you have a problem, because it contains an even amount of numbers - the number that is in the exact center is 5.5, and not 5.

    Assuming you want integer values, you're going to have an imbalance, because there are 4 digits smaller than 5 and 5 digits larger than 5.

    So how do you want to deal with the imbalance?

    - jim
    Last edited by jbum; 03-15-2004 at 05:16 AM.

  5. #5
    Junior Member
    Join Date
    Dec 2003
    Location
    seattle
    Posts
    8
    I do want all the numbers in the range to be returnable.
    ...what I meant before was - starting with r=5 and adding 5 negative 1's or positive 1's in any combination you couldn't ever add up to 1,3,5 etc.

    As far as the exact center point, I am more than happy to have the range be odd so there's an exact center number. Say 1 to 11. I am also fine with 0 to 10 if that works out.

    Thanks for working though this with me. I know it's really hard to write an explanation of what you want done, and even harder to read someone elses!

  6. #6
    Senior Member
    Join Date
    Mar 2002
    Posts
    183
    I see what you mean not being able to get even numbers. Why don't you just start with 10, and do your add 1 subtract 1 thing till you get odd numbers from 0-20. Then just 1=1 3=2 5=3....if you see what i mean. Now you have 1-10 including evens.

  7. #7
    avatar free
    Join Date
    Jul 2002
    Location
    UK
    Posts
    835
    Hmm, a nice and simple take on the subject jbum.

    But here's what I was taught, and it can be used for any "probability density distribution" ( Don't worry, just big words meaning what type of numbers are spat out ). It was called the ( Inverse ) Transform Method.

    Basically, if you can put the "line" that you want the random numbers to be under ( in this case shaped like a bell curve ) into an analytical form ( like y = f(x) ) and it has as inverse function, then you can use that inverse, stick in a ( uniform ) random number, and it'll be scaled to the right amount. It's a bit complicated and I can't describe it very well. I think it would be over the top in most cases anyway.

    The other simple version, albeit a bit inefficient, is a simple "look and throw away if wrong" approach. Pick 2 ( uniform ) random numbers, x and y. Plug those into the curve formula, and if the point you chose was under the curve, great, keep x. Otherwise throw it away and check again. It's the fact you need 2 numbers and you might throw some away that makes it inefficient, but unless you're doing some major monte carlo method simulations then it's no worries!
    jonmack
    flash racer blog - advanced arcade racer development blog

  8. #8
    Senior Member jbum's Avatar
    Join Date
    Feb 2004
    Location
    Los Angeles
    Posts
    2,920
    Ah, good call - I didn't notice that behavior.

    Here's a way to get past that problem. It's twice as inefficient, because I jump up and down in increments of .5.

    Here's the function:

    Code:
    // returns R in which 0 >= R <= max,
    // with Guassian distribution (bell curve)
    function GaussRandom(max)
    {
      var r = max/2;
      for (var j = max; j > 0; --j) {
       r += Math.random()-.5;
      }
      return Math.round(r);
    }
    and here's a sample test:

    Code:
    ary = new Array(10);
    for (i = 0; i < 10000; ++i) {
        var r = GaussRandom(10);
     ary[r]++;
    }
    for (i = 0; i <= ary.length; ++i)
     trace(i + ": " + ary[i]);
    and here are the test results for 10000 tries (looks pretty bell-curvy to me)
    :

    Code:
    0: 0
    1: 0
    2: 19
    3: 461
    4: 2454
    5: 4116
    6: 2450
    7: 476
    8: 23
    9: 1
    10: 0
    This routine is accurate, the problem is that it is inefficient, because it loops. The larger the range you want, the longer it takes.

    I've been looking for a way to do it using only one call to Math.random().

    This involves something like an easing function that pinches the value of Random() towards .5 - basically what jonmack was talking about. Unfortunately, jonmack didn't provide the actual function, and that's the hard part.

    Basically we're looking for a function that you pass Math.random() to (a value going from 0-1) and it pinches the value towards .5 This produces a graph that looks like this.

    Code:
     _______/
    /
    The following code is *close* to what I'm looking for, but it's not quite a bell curve. For large max (or a game, where accuracy isn't that important), it is far more efficient, however.

    Code:
    // take a value from 0-1 and 'pinch' it
    // towards the middle (0.5)
    function PinchRand(x)
    {
      return 0.5 +  Math.pow(((Math.random()-.5)*2),7)/2;
    }
    
    // Does not produce a true bell curve distribution, but similar.  Much more efficient than GaussRandom() for large 'max'
    function GaussRandom2(max)
    {
      return Math.round(PinchRand()*max);
    }
    Here's a comparison of the two functions for a run of 10000. You'll see that GaussRandom2 is more likely to go to the edges, and has a higher spike in the middle. If you're using this for a game, it probably is sufficient, but if
    you want true bell-curve statistics, it's way off.

    Code:
    (GaussRandom, followed by GaussRandom2)
    0:   0,    80
    1:   0,    178
    2:   13,   221
    3:   529,  339
    4:   2456, 614
    5:   4130, 7202
    6:   2406, 586
    7:   444,  296
    8:   22,   214
    9:   0,    200
    10:  0,   70

    - jim
    Last edited by jbum; 03-15-2004 at 06:25 PM.

  9. #9
    Junior Member
    Join Date
    Dec 2003
    Location
    seattle
    Posts
    8
    Wow. It's far closer than anything I could muster and perfect for my application which is a game of sorts - a kind of dice roll probability thingy.

    If you want to keep refining it be my guest, but you have given me two very viable options and I'm sure I could muck with it a bit more if I need more or less 'curviness'!

    Thanks a ton.

  10. #10
    Senior Member jbum's Avatar
    Join Date
    Feb 2004
    Location
    Los Angeles
    Posts
    2,920
    Your dice comment gave me an idea. This one's pretty cheap, and it's a proper bell curve.

    If you give it 10, it makes two 5-sided dice, roll's up and adds the result.

    // returns a value from 2 to max
    //
    function GaussRandomDice(max)
    {
    var sides = max/2;
    return 2 +
    Math.floor(Math.random()*sides) +
    Math.floor(Math.random()*sides);
    }

  11. #11
    Senior Member jbum's Avatar
    Join Date
    Feb 2004
    Location
    Los Angeles
    Posts
    2,920
    Your dice comment gave me an idea. This one's pretty cheap, cpu-wise, and it's a proper bell curve.

    If you give it 10, it makes two 5-sided dice, roll's up and adds the result.

    Code:
    // returns a value from 2 to max
    //
    function GaussRandomDice(max)
    {
      var sides = max/2;
      return 2 + 
            Math.floor(Math.random()*sides) +
            Math.floor(Math.random()*sides);
    }

  12. #12
    Senior Member
    Join Date
    May 2001
    Posts
    1,838
    The last algorithm is not really a bell curve. It is a linear "triangle".

    We would assume that when the number of tests went large, ideally the random function is expected to distribute dice number with even chances.

    For example, we have dice numbers of 0~5. For the first random function in the script, it returns equal chance of 0~5, and for each number 0~5, the second random function returns eaqual chance of hit for those number 0~5. So, the result of hit is something like this:
    Code:
    xxxxxx
     xxxxxx
      xxxxxx
       xxxxxx
        xxxxxx
         xxxxxx
    ---------------
    0123456789A  - sum of hit
    Thus, if the chance of sum up as '0' is C, the chance of sum-up as '1' is 2*C and the chance of '2' should be 3*C........;

    So, the result of sum-up of 2 dice throwing does not distribute as a bell curve.
    ----------------------------------
    For the "falling leaf in the wind" algorithm, the equation seems to be something like y=K/(Max-x)!*(x)!; (I am not very sure about this, I just did a simple calculation only). I dont know whether this is a bell curve or not. Anyway, it looks more like "bell" curve than the dice algorithm.
    ----------------------------------
    The reason why it always return even number not odd number is that, we give the falling leaf only two options - forward or backward. That is 1 or -1; If we sum up 10 steps, we always get an even number. If we sum up 11 steps, we always get an odd number.

    Here a question confused myself. Why dont we give it 3 options. Forward, backward and straight. That is 1,0,-1. However, for what reason could we arbiturarily assume the chace of falling straight be the same as falling forward ? So, the algorithm confused myself.

    Sorry, I could not give any answer.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center