Question: Suppose you have a random number generator randn() that returns a uniformly distributed random number between 0 and n-1. Given any number m, write a random number generator that returns a uniformly distributed random number between 0 and m-1.
My answer:
-(int)randm() {
int k=1;
while (k*n < m) {
++k;
}
int x = 0;
for (int i=0; i<k; ++i) {
x += randn();
}
if (x < m) {
return x;
} else {
return randm();
}
}
Is this correct?
You're close, but the problem with your answer is that there is more than one way to write a number as a sum of two other numbers.
If m<n
, then this works because the numbers 0,1,...,m-1
appear each with equal probability, and the algorithm terminates almost surely.
This answer does not work in general because there is more than one way to write a number as a sum of two other numbers. For instance, there is only one way to get 0
but there are many many ways to get m/2
, so the probabilities will not be equal.
Example: n = 2
and m=3
0 = 0+0
1 = 1+0 or 0+1
2 = 1+1
so the probability distribution from your method is
P(0)=1/4
P(1)=1/2
P(2)=1/4
which is not uniform.
To fix this, you can use unique factorization. Write m
in base n
, keeping track of the largest needed exponent, say e
. Then, find the biggest multiple of m
that is smaller than n^e
, call it k
. Finally, generate e
numbers with randn()
, take them as the base n
expansion of some number x
, if x < k*m
, return x
, otherwise try again.
Assuming that m < n^2
, then
int randm() {
// find largest power of n needed to write m in base n
int e=0;
while (m > n^e) {
++e;
}
// find largest multiple of m less than n^e
int k=1;
while (k*m < n^2) {
++k
}
--k; // we went one too far
while (1) {
// generate a random number in base n
int x = 0;
for (int i=0; i<e; ++i) {
x = x*n + randn();
}
// if x isn't too large, return it x modulo m
if (x < m*k)
return (x % m);
}
}
It is not correct.
You are adding uniform random numbers, which does not produce a uniformly random result. Say n=2 and m = 3, then the possible values for x are 0+0, 0+1, 1+0, 1+1. So you're twice as likely to get 1 than you are to get 0 or 2.
What you need to do is write m in base n, and then generate 'digits' of the base-n representation of the random number. When you have the complete number, you have to check if it is less than m. If it is, then you're done. If it is not, then you need to start over.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With