Выборка отклонения - это путь, если вы хотите иметь равномерное распределение по результату. Общеизвестно, что делать что-то умнее сложно. Например, использование оператора по модулю приводит к неравномерному распределению значений результата для любого числа, которое не является степенью 2.
Алгоритм в вашем посте, однако, может быть улучшен путем отбрасывания ненужных наиболее значимых битов. (См. Ниже.)
Вот как стандартный Java API реализует Random.nextInt(int n)
:
public int nextInt(int n) {
[...]
if ((n & -n) == n) // i.e., n is a power of 2
return (int)((n * (long)next(31)) >> 31);
int bits, val;
do {
bits = next(31);
val = bits % n;
} while (bits - val + (n-1) < 0);
return val;
}
А в комменсе вы можете прочитать:
Алгоритм немного хитрый. Он отклоняет значения, которые могут привести к неравномерному распределению (из-за того, что 2 31 не делится на n ). Вероятность отклонения значения зависит от n. Худший случай - n = 2 30 + 1, для которого вероятность отклонения равна 1/2, а ожидаемое число итераций до завершения цикла равно 2.