сгенерируйте случайное число от 1 до x, где меньшее число более вероятно, чем большее


Это скорее вопрос математики/общего программирования, но я программирую на PHP, и это имеет значение.

Я думаю, что самый простой способ объяснить это на примере.

Если диапазон составляет от 1 до 10.

Я хочу сгенерировать число от 1 до 10, но, скорее всего, оно меньше, чем высокое.

Единственный способ, который я могу придумать, - это создать массив из 10 элементов, равных 1, 9 элементов, равных 2, 8 элементов, равных 3.....1 элемент, равный 10. Затем сгенерируйте случайное число на основе количества элементов.

Проблема в том, что я потенциально имею дело с 1-100000, и этот массив был бы смехотворно большим.

Итак, как лучше всего это сделать?

Author: Pablo, 2010-07-21

13 answers

Сгенерируйте случайное число от 0 до случайного числа!

 25
Author: Tim Rogers, 2010-07-21 15:34:23

Сгенерируйте число от 1 до foo(n), где foo выполняет алгоритм над n (например, логарифмическую функцию). Затем переверните foo() на результат.

 11
Author: Quentin, 2010-07-21 15:29:38

Сгенерируйте число n, которое равно 0 <= n < 1, умножьте его на себя, затем умножьте на x, запустите его и добавьте 1. Извините, что я слишком давно использовал php для написания кода в нем

 4
Author: tig, 2010-07-21 15:29:51

Вы могли бы сделать

$rand = floor(100000 * (rand(0, 1)*rand(0, 1)));

Или что-то в этом роде

 3
Author: b8b8j, 2010-07-21 15:30:41

В основном существует два (или больше?) способы отображения равномерной плотности на любую функцию распределения: Выборка обратного преобразования и Выборка отбраковки . Я думаю, что в вашем случае вам следует использовать первое.

 3
Author: NikiC, 2010-07-21 15:52:29

Быстро и просто:

rand(1, rand(1, n))
 3
Author: Andy, 2010-07-21 17:34:31

Я думаю, что это может быть то, что вы ищете:

Случайный по весу

 2
Author: DrunkenBeard, 2017-05-23 12:15:07

Что вам нужно сделать, так это сгенерировать случайное число с большим интервалом (предпочтительно с плавающей запятой) и отобразить его в [1,10] неравномерным образом. Какой именно способ зависит от насколько гораздо более вероятно, что вы хотите, чтобы 1 был, чем 9 или 10.

Для решений на языке C см. эти библиотеки . Вы можете найти применение для этого в PHP.

 0
Author: Pontus Gagge, 2010-07-21 15:31:22

Вообще говоря, похоже, что вы хотите получить случайное число из распределения Пуассона , а не из [равномерного распределения](http://en.wikipedia.org/wiki/Uniform_distribution_ (непрерывный)). На вики-странице, упомянутой выше, есть раздел, в котором конкретно указано, как вы можете использовать непрерывное распределение для создания псевдо-пуассоновского распределения... проверьте это. Обратите внимание, что вы можете захотеть проверить различные значения λ, чтобы обеспечить распределение работает так, как вы хотите.

 0
Author: eykanal, 2010-07-21 15:47:23

Это зависит от того, какое распределение вы хотите иметь точно, т. Е. Какое число должно появиться с какой вероятностью.

Например, для четного n вы могли бы сделать следующее: сгенерировать одно целое случайное число x от 1 до n/2 и сгенерировать второе число от 1 до n+1. Если y > x, вы генерируете x, в противном случае вы генерируете n-x+1. Это должно дать вам распределение в вашем примере.

 0
Author: maschka, 2010-07-21 15:55:14

Я думаю, что это должно дать запрошенное распределение:

Сгенерируйте случайное число в диапазоне 1.. x. Сгенерируйте другое число в диапазоне 1..x+1. Верните минимум из двух.

 0
Author: Accipitridae, 2010-07-21 18:15:48

Давайте подумаем о том, как ваша идея массива изменяет вероятности. Обычно каждый элемент от 1 до n имеет вероятность 1/n и, следовательно, одинаково вероятен.

Поскольку у вас есть n записей для 1, n-1 записей для 2...1 запись для n, то общее количество записей, которые у вас есть, представляет собой арифметический ряд. Сумма арифметического ряда, насчитывающего от 1 до n, равна n(1+n)/2. Итак, теперь мы знаем, что вероятность каждого элемента должна использовать это в качестве знаменателя.

Элемент 1 содержит n записей, поэтому его вероятность равна n/n(1+n)/2. Элемент 2 равен n-1/n(1+n)/2... n равно 1/n(1+n)/2. Это дает общую формулу числителя в виде n+1 -i, где i - число, которое вы проверяете. Это означает, что теперь у нас есть функция вероятности любого элемента как n-i+1/n(1+n)/2. все вероятности находятся в диапазоне от 0 до 1 и по определению равны 1, и это является ключом к следующему шагу.

Как мы можем использовать эту функцию, чтобы исказить количество появлений элемента? Это проще с непрерывными распределениями (т. е. удваивается вместо ints), но мы можем это сделать. Сначала давайте составим массив наших вероятностей, назовем его c, составим их текущую сумму (cumsum) и сохраним ее обратно в c. Если это не имеет смысла, это просто цикл, подобный


for(j=0; j < n-1; j++)
   if(j) c[j]+=c[j-1]

Теперь, когда у нас есть это кумулятивное распределение, сгенерируйте число i от 0 до 1 (двойное, а не int. Мы можем проверить, находится ли я между 0 и c[0], верните 1. если я нахожусь между c[1] и c[2], верните 2...вплоть до n. например {[1]}

Это будет распространять целые числа в соответствии с рассчитанными вами вероятностями.

 0
Author: frankc, 2010-07-21 19:10:33
<?php 
//get random number between 1 and 10,000
$random = mt_rand(1, 10000); 
?>
 -1
Author: BENN1TH, 2015-03-09 09:49:52