I'd start by normalizing the requested range (later just add min
to the random generated number):
int max_rnd = max - min;
Then generate a equally distributed random number in the range 1
to pow(2, max_rnd+1) - 1
int rnd_limit = (1 << (max_rnd + 1)) - 1;
int rnd = (rand() % rnd_limit) + 1;
Round down the base-2-logarithm of the generated random number. The translation of rnd
will follow this pattern:
floor(log2(1)) -> 0
floor(log2(2)) -> 1
floor(log2(3)) -> 1
floor(log2(4)) -> 2
...
floor(log2(7)) -> 2
floor(log2(8)) -> 3
...
floor(log2(15)) -> 3
...
So the distribution of results will be the reverse of the expected (double instead of half for higher numbers) but thats easy to change. Effectively, the floor(log2(rnd))
is computing the position of the highest 1 bit in rnd
, so it can be implemented with a bitshift loop:
int log2_rnd = 0;
while ((rnd >> log2_rnd) != 1)
{
++log2_rnd;
}
Time for the actual result:
return (max_rnd - log2_rnd) + min;
Not covered here: Accuracy of "equally distributed" numbers generated by rand()
(specially in combination with modulo) and upper limit of generated numbers.