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?
rand returns pseudo-random integral number:
Now, regarding the less-lengthy way, you can use switch-case construction, or a series of conditional operators
?:
(which will make your code short and unreadable:).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:
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.
Assuming
rand()
is good then your code will work with only a very small bias to the lower X numbers, where X is RAND_MAX % 7. It's much more likely that you won't get the desired odds due to the quality of the implementation ofrand()
. If you find that to be the case then you'll want to use an alternative random number generator.C++11 introduces the header
<random>
which includes several quality RNGs. Here's an example:Given this, when you call
rand()
you will get a number from 1 to 7 each with equal probability. (And you can choose different engines if for different quality and speed characteristics.) You can then use this to implement the if-else conditions your example currently uses withstd::rand()
. However<random>
allows you to do even better using one of their non-uniform distributions. In this case what you want isdiscrete_distribution
. This distribution allows you to explicitly state the weights for each value from 0 to n.This should give numbers with a distribution as even as
rand
can handle, and without the bigif
switch.Note this does have a theoretically possible infinite loop, but the statistical odds of it staying in the loop for even are minuscule. The odds of it staying in the loop twice is quite close to the odds of winning the California Super Lotto Jackpot. Even if every person on the planet got five random numbers, it probably wouldn't stay in the loop three times. (Assuming a perfect RNG.)
Just another way: