If you don't want to do division, there is good property of random values from math. You can exclude any range.
Let random() - function that gives random values within some range.
Code: Select all
do { x = random(); }
while( !in_range(x) );
function in_range returns true if x good for you.
For example, I have 12 characters, I want to get random character.
Code: Select all
do { x = random(); }
while ( x >= 12 );
x = character id from 0 to 11.
BUT, if random has a large range, then it may take a lot of iterations.
So, assuming that range is power of 2, we can improve:
Code: Select all
do { x = random()&(16-1);}
while ( x >= 12 );
No division.
Notice: for this case, common method: x = random()%12. Bad method! It will be not uniform.
About properties.
First, if you repeat random generation when value does not satisfy your requirements, then distribution does "not changed" in some terms. In this case, "not changed" means that ratio between two different probabilities, does not changed. For example, you have random value in set {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15} with uniform distribution. If you repeat random generation when value is in set {2,7,8,10,12}, then you will achieve uniform distribution in set {0,1,3,4,5,6,9,11,13,14,15}. It's easy to prove.
Second, if range is power of 2, and distribution is uniform, then you can remap range into smaller range just taking any of bits.