Случайное число в диапазоне с равной вероятностью
это может быть больше связано с математикой, чем C#, но мне нужно решение c#, поэтому я помещаю его здесь.
мой вопрос о вероятности генераторов случайных чисел, более конкретно, если все возможные значения с равной вероятностью.
Я знаю, что есть случайные.Next (int, int) метод, который возвращает число между первым целым и последним (причем последнее является исключительным).
Random.Next()
[без перегрузок] вернет значение между 0 и Int32.MaxValue (который составляет 2147483647) - 1, поэтому 2147483646.
если мне нужно значение от 1 до 10, я могу вызвать Random.Next(1, 11)
для этого, однако, каждое значение между 1 и 10 имеет равную вероятность возникновения?
например, диапазон равен 10, поэтому 2147483646 не полностью делится на 10, поэтому значения 1-6 имеют немного более высокую вероятность возникновения (потому что 2147483646 % 10 = 6
). Это, конечно, предполагает, что каждое значение в Random.Next()
[без overloads] возвращает значение от 0 до 2147483646 с равной вероятностью.
как можно гарантировать, что каждое число в диапазоне, имеет равную вероятность происходящего? Скажем, для системы лотерейного типа, где было бы несправедливо для некоторых людей иметь более высокую вероятность, чем другие, я не говорю, что буду использовать C#, встроенный в RNG для этого, я просто использовал его в качестве примера.
4 ответов
Я отмечаю, что никто на самом деле не ответил на мясной вопрос в вашем посте:
например, диапазон равен 10, поэтому 2147483646 не полностью делится на 10, поэтому значения 1-6 имеют немного более высокую вероятность возникновения (потому что 2147483646% 10 = 6). Это, конечно, предполагает, что каждое значение внутри Random.Next () [без перегрузок] возвращает значение от 0 до 2147483646 с равной вероятностью.
как бы убедиться, что каждый номер внутри диапазон имеет равную вероятность возникновения?
правильно, поэтому вы просто выбрасываете значения, которые вызывают дисбаланс. Например, предположим, что у вас есть RNG, который может производить равномерное распределение по { 0, 1, 2, 3, 4 }
, и вы хотели использовать его для создания равномерного распределения по { 0, 1 }
. Наивная реализация: draw from {0, 1, 2, 3, 4}
а затем верните значение % 2
; это, однако, очевидно, приведет к предвзятому образцу. Это происходит потому, что, как вы заметили,5
(количество элементов) не делится равномерно на 2. Поэтому вместо этого бросайте любые розыгрыши, которые производят значение 4
. Таким образом, алгоритм будет
draw from { 0, 1, 2, 3, 4 }
if the value is 4, throw it out
otherwise, return the value % 2
вы можете использовать эту основную идею для решения общей проблемы.
однако каждое значение между 1 и 10 имеет равную вероятность возникновения?
Да, это делает. От MSDN:
выбираются псевдослучайные числа с равным вероятностью из конечного набора чисел.
Edit: по-видимому, документация не соответствует текущей реализации .Сеть. В документации говорится, что чертежи являются единообразными, но код предполагает, что это не так. Однако это не отрицает того факта, что это разрешимая проблема, и мой подход-один из способов ее решения.
тестовая программа:
var a = new int[10];
var r = new Random();
for (int i = 0; i < 1000000; i++) a[r.Next(1, 11) - 1]++;
for (int i = 0; i < a.Length; i++) Console.WriteLine("{0,2}{1,10}", i + 1, a[i]);
выход:
1 99924 2 100199 3 100568 4 100406 5 100114 6 99418 7 99759 8 99573 9 100121 10 99918
вывод:
каждое значение возвращается с равной вероятностью.
C#, встроенный в RNG, как вы ожидаете, равномерно распределен. Каждое число имеет равную вероятность возникновения заданного диапазона для Next(min, max)
.
вы можете проверить это сами (у меня есть), взяв, скажем, образцы 1M и сохранив, сколько раз каждое число на самом деле появляется. Вы получите почти плоскую кривую, если нарисуете ее.
также обратите внимание, что каждое число имеет равную вероятность не означает, что каждое число будет происходить одинаковое количество раз. если вы смотрите на случайные числа от 1 до 10, в 100 итерациях, это не будет четным распределением вхождения 10x для каждого числа. Некоторые числа могут возникать 8 раз, а другие 12 или 13 раз. Однако с большим количеством итераций это имеет тенденцию несколько выравниваться.
кроме того, поскольку это упоминается в комментариях, я добавлю: если вы хотите что-то более сильное, посмотрите криптографические PRNGs. Mersenne Twister особенно хорош из того, что я видел (быстрый, дешевый для вычисления, огромный period) и имеет реализации с открытым исходным кодом в C#.
Ashes и dtb неверны: вы правы, подозревая, что некоторые числа будут иметь больше шансов произойти, чем другие.
когда вы называете .Next(x, y)
, есть y-x возможные возвращаемые значения. Интернет .Net версии 4.0 Random
class вычисляет возвращаемое значение на основе возвращаемого значения NextDouble()
(это несколько упрощенное описание).
очевидно, что набор возможных двойных значений конечен, и, как вы заметили, он не может быть кратным размеру набора возможные возвращаемые значения .Next(x, y)
. Поэтому, предполагая, что набор входных значений is равномерно распределенные, некоторые выходные значения будут иметь немного большую вероятность возникновения.
Я не знаю, сколько числовых двойных значений есть (т. е., исключая бесконечность и значения NaN), но это, безусловно, больше, чем 2^32. В вашем случае, если мы примем 2^32 значения, для аргумента, то мы должны сопоставить 4294967296 входов с 10 выходами. Некоторые величины будет иметь 429496730 / 429496729 большую вероятность возникновения, или 0.00000023283064397913028110629 процентов больше. Фактически, так как количество входных состояний равно больше чем 2^32, разница в вероятности будет еще меньше.