Вы близки, но проблема с вашим ответом в том, что существует несколько способов записать число в виде суммы двух других чисел.
Если m<n
, то это работает, потому что числа 0,1,...,m-1
появляются с равной вероятностью, и алгоритм почти наверняка завершается.
Этот ответ вообще не работает, потому что существует более одного способа записать число в виде суммы двух других чисел. Например, есть только один способ получить 0
, но есть много способов получить m/2
, поэтому вероятности не будут равны.
Пример : n = 2
и m=3
0 = 0+0
1 = 1+0 or 0+1
2 = 1+1
так что распределение вероятностей по вашему методу
P(0)=1/4
P(1)=1/2
P(2)=1/4
который не является равномерным.
Чтобы исправить это, вы можете использовать уникальную факторизацию. Напишите m
в базе n
, отслеживая наибольший необходимый показатель, скажем, e
. Затем найдите наибольшее значение, кратное m
, которое меньше n^e
, назовите его k
. Наконец, сгенерируйте e
чисел с помощью randn()
, возьмите их за базовое n
расширение некоторого числа x
, если x < k*m
, верните x
, в противном случае попробуйте снова.
Если предположить, что m < n^2
, то
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);
}
}