Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will this give me proper random numbers based on these probabilities? C++

Code:

int random = (rand() % 7 + 1)
if (random == 1) { } // num 1
else if (random == 2) { } // num 2
else if (random == 3 || random == 4) { } // num 3
else if (random == 5 || random == 6) { } // num 4
else if (random == 7) { } // num 5

Basically I want each of these numbers with each of these probabilities: 1: 1/7 2: 1/7 3: 2/7 4: 2/7 5: 1/7

Will this code give me proper results? I.e. if this is run infinite times, will I get the proper frequencies? Is there a less-lengthy way of doing this?

like image 625
DillPixel Avatar asked Nov 29 '11 19:11

DillPixel


2 Answers

Not, it's actually slightly off, due to the way rand() works. In particular, rand returns values in the range [0,RAND_MAX]. Hypothetically, assume RAND_MAX were ten. Then rand() would give 0…10, and they'd be mapped (by modulus) to:

0  → 0
1  → 1
2  → 2
3  → 3
4  → 4
5  → 5
6  → 6
7  → 0
8  → 1
9  → 2
10 → 3

Note how 0–3 are more common than 4–6; this is bias in your random number generation. (You're adding 1 as well, but that just shifts it over).

RAND_MAX of course isn't 10, but it's probably not a multiple of 7 (minus 1), either. Most likely its a power of two. So you'll have some bias.

I suggest using the Boost Random Number Library which can give you a random number generator that yields 1–7 without bias. Look also at bames53's answer using C++11, which is the right way to do this if your code only needs to target C++11 platforms.

like image 55
derobert Avatar answered Oct 02 '22 21:10

derobert


Just another way:

float probs[5] = {1/7.0f, 1/7.0f, 2/7.0f, 2/7.0f, 1/7.0f};
float sum = 0;
for (int i = 0; i < 5; i++)
  sum += probs[i]; /* edit */
int rand_M() {
  float f = (rand()*sum)/RAND_MAX; /* edit */
  for (int i = 0; i < 5; i++) {
    if (f <= probs[i]) return i;
    f -= probs[i];
  }
  return 4;
}
like image 39
perreal Avatar answered Oct 02 '22 23:10

perreal