4
\$\begingroup\$

In an XNA book I read that this code does an action with a 0.2% of probability but I don't' understand why:

float chance = 0.2f;

if((float)rand.Next(0,1000) / 10 <= chance)
{
...
}

I understand the statement, but not the reasoning for that equation. Can anyone explain me, please?

\$\endgroup\$
1
  • \$\begingroup\$ Is your actual question: 'why do it like this' or is it 'how does this work'? If it's the first then I can only say: no idea why, else see all the answers :). \$\endgroup\$
    – Roy T.
    Commented Jul 23, 2012 at 14:21

4 Answers 4

11
\$\begingroup\$
(float)rand.Next(0,1000) / 10

Picks a random number between 0 and 1000, the divides by 10. This gives you a random number between 0 and 100. If that random number is less than or equal to your chance (<= .2), then the statement is true and whatever is inside the if statement is executed.

If you want to get a .2% chance, that means that for every .2% of the times you run this code it will be true. So how do we do that? Pick a random number between 0 and 100, if it's less than .2 it's true.

Throw a random dart at this image:

enter image description here

If the dart were truly random, you'd expect it to hit blue 50% of the time and red 50% of the time. So we want something to happen 50% of the time, this is what we would use. So what if we wanted it to happen .2% of the time? I means our image needs to look at bit less equal.

enter image description here

Throw that random dart at this image and you'll hit blue .2% of the time.

EDIT to address your comment

The thing about random numbers is that they don't care about the number that was chosen before them. If you were to flip a fair coin, you have a 50% chance of it landing on heads and a 50% chance of it landing on tails. So should would you be surprised if you flipped it twice in a row and it came up heads both times? No, I don't think you would. How about if you flipped it 6 times, would you be surprised if if came out 4 tails and 2 heads? No that is totally possible. How about 6 heads in a row? Well that is certainly less expected, but it's not impossible. What about 100 flips and they're all heads? Now that seems totally impossible. But it's not, it's just very, very unlikely. Here's the thing though. If you're on flip 99 and they've all been heads up until that point, there's still only a 50% chance that the next flip will be heads too. The next flip has nothing to do with any of the previous flips or any of the flips to come after. Just because you've had 99 heads in a row doesn't make it any more likely that the next flip will be tails (see Gambler's fallacy). However as the sample size grows the number of heads and number of tails will start to equalize. See this simulated coin toss distribition:

enter image description here

As you can see, there are times where if you stopped right then, things would look very unbalanced. But as the sample size continues to grow, it does start to equalize towards 50/50. You can also see that I got lucky and this animated gif matches the color scheme I picked :).

Probability belongs to statistics. Statistics is one thing that people are typically not good at (if you need proof of that, just look at all the lottery players). It is however very beneficial to study statistics. It'll help you in programming and life in general.

Basically what you should take away from this is:

  • Random numbers are not affected by any number that appeared before or after them.
  • With small sample sizes, the distribution of probability might look wrong, so don't worry.
  • The lottery is a tax for people who don't know statistics
  • Random numbers do not guarantee their distribution
  • Know statistics well and you will be a superhero
\$\endgroup\$
7
  • \$\begingroup\$ Yes, maybe I explain the question bad! I understand the statement, I don't understand why that equation! P.S. A number is taken between 0 and 999... \$\endgroup\$
    – xdevel2000
    Commented Jul 23, 2012 at 14:13
  • 2
    \$\begingroup\$ @xdevel2000: you should update the question accordingly to explain a little bit more what you expect form the answers. I tried to give a different explanation, if that was what you were looking for. \$\endgroup\$ Commented Jul 23, 2012 at 14:27
  • \$\begingroup\$ Yes, good answer and thanks for the images :) However when you say that having 50f give us a 50% of probability if I run the code with this value I have some time that the number generated, some time, is not 50% lesser than 50 and 50% greater then 50. In fact I have, for example, 76 59,7 95,5 31,4 so 3 time greater than 50 and one time lesser. Why? \$\endgroup\$
    – xdevel2000
    Commented Jul 24, 2012 at 7:11
  • \$\begingroup\$ Down voter care to comment? \$\endgroup\$
    – House
    Commented Jul 24, 2012 at 15:31
  • \$\begingroup\$ @Byte56: great and congratulation for this answer, very detailed and analytics on probability and statistics in general. Thanks a lot. Anyway, I wanted to ask you one more thing: why do you keep saying that (float) rand.Next (0.1000) gives a number between 0 and 1000 and not between 0 and 999? \$\endgroup\$
    – xdevel2000
    Commented Jul 25, 2012 at 7:11
12
\$\begingroup\$

There is no reason. It's just a stupid thing which works but is completely unnecessary. The author probably just wanted to write down the chance as percent and not as permille .

Better is:

// In Permille: 2‰ == 0.2% == 0.002
int chance=2;
if(rand.Next(0, 1000) <= chance)
{
  [...]
}

It will give you the same result but without those divisions and conversions to float.

Or if you prefer floating points over fixed numbers:

double chance=0.002;
if(rand.NextDouble() <= chance)
{
  [...]
}
\$\endgroup\$
2
  • 3
    \$\begingroup\$ +1, seems the most likely explanation to me too. I'd be more inclined to go with the NextDouble alternative as there's less chance of someone coming along later and "correcting" it - all the others have some degree of ambiguity or lack of clarity as to what's going on, and good code shouldn't have that. \$\endgroup\$ Commented Jul 23, 2012 at 17:38
  • 3
    \$\begingroup\$ As a native English speaker, "percent" is a very commonly used word, whereas "per mil" is extremely esoteric. \$\endgroup\$
    – Jimmy
    Commented Jul 23, 2012 at 22:26
8
\$\begingroup\$

The part (float)rand.Next(0, 1000) generates a number between 0.0f and 999.0f inclusively.

Then, you divide it by 10 to get a number from 0.0f to 99.9f.

Checking if the number is below or equal to 0.2f checks if we hit the desired percentage, hence giving it a 0.2% chance of entering that if block.

Why the equation (float)rand.Next(0, 1000) / 10? Because you want to at least have a chance of getting into that if block.

If it had been simply rand.Next(0, 100), it would have entered the loop 1% of the time (when it would have given 0).

If my maths are not actually failing me this morning, by using the (float)rand.Next(0, 1000) / 10, you get the range from 0 to 2 (3 numbers) that give you a chance of entering that loop (since they are the only that x < 10 >= 0.2). 3/1000 gives your 0.003, or 0.3% chance (you'd have to remove that = from <= to get that actual 0.2%).

Instead, I recommend you to use rand.NextDouble() in your code. It is less obscure for other programmers (or yourself after a few months not looking at the piece of code) and more flexible.

Example of use in your context:

const float Chance = 0.2f; // I gave them programmers consts, programmers loooove const variables.
const float Percent = Chance / 100.0f; // divide by 100 to actually get the 0.2%

if (rand.NextDouble() < Percent)
{
    ...
}
\$\endgroup\$
4
  • 3
    \$\begingroup\$ Programmers seem to love unused const variables :) (Otherwise, good answer, +1) \$\endgroup\$
    – bummzack
    Commented Jul 23, 2012 at 14:48
  • \$\begingroup\$ Interesting answer but, excuse me, why do you say that (float)rand.Next(0, 1000) / 10 get the range from 0 to 2 (3 numbers)? Maybe my maths is very rusty :) \$\endgroup\$
    – xdevel2000
    Commented Jul 23, 2012 at 15:40
  • 3
    \$\begingroup\$ 0, 1, and 2 out of the random function that is going to give you from 0-999. After being divided by 10 those values will be 0.0f, 0.1f, and 0.2f all of which are less than or equal to 0.2f. If you limit it to just less than 0.2f, you'll get only 0.0f and 0.1f triggering (0 and 1 from the rand) which is 2/1000 (0.2%) of the possible results. \$\endgroup\$
    – Lunin
    Commented Jul 23, 2012 at 17:46
  • \$\begingroup\$ @bummzack: silly me, I didn't even notice, even after writing the comment. \$\endgroup\$ Commented Jul 24, 2012 at 5:05
4
\$\begingroup\$

Sorry I misinterpreted your question, here is the actually working code simplified as much as possible so that it's easier to see what's going on.

double chance = 0.2; //we use real percentages now

//We choose a random number in [0...999] because we want enough precision for 1000
//different chances (100% to 0.1% or even 0%), we multiply our chance by 10 to
//move it from the 0.0~100 range into the 0~1000 range
if(Random.Next(0,1000) < chance * 10)
{
   ...
}

This is the old, wrong answer, here for reference only, I missed that it was .2% and not the 2% I assumed

I don't get the equation either its convoluted, we could do without the weird division by and 10 and it's not clear why a random number in [0...999] is chosen instead of a random number in [0..99], maybe that's why you're having trouble with it. Let's get rid of the unnecessary cast and the division and clean it up as much as we can. The equivalent and, in my opinion, much more readable version would be:

double chance = 2; //we use real percentages now
if(Random.Next(0, 100) < chance)
{
    ...
}
\$\endgroup\$
4
  • \$\begingroup\$ Perhaps the random number generator they were using was producing ints. \$\endgroup\$
    – House
    Commented Jul 23, 2012 at 14:27
  • \$\begingroup\$ .2 out of 100 is .2%, not 2%. So the real percentage is still .2f. \$\endgroup\$
    – House
    Commented Jul 23, 2012 at 14:34
  • \$\begingroup\$ Byte56, argh -1 for me, you're spot on, they were looking for .2% not 2%, I missed that dreaded point. \$\endgroup\$
    – Roy T.
    Commented Jul 23, 2012 at 14:37
  • \$\begingroup\$ Na, it's a good answer. +1 \$\endgroup\$
    – House
    Commented Jul 23, 2012 at 14:55

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .