Это сайт — моя персональная записная книжка. Интересна мне, по большей части, история, своя жизнь и немного программирование.

Генерация «трафки™» или распределение по весам

Дима Смирнов применил интересное решение для генерации «трафок» на «Блоговаре»:

$rb   = str_pad (decbin (mt_rand (0,64)),6,"0", STR_PAD_LEFT);
$herb = (int) strpos ($rb, "1");

Смысл в том, что каждое следующее значение должно выпадать с вдвое меньшей вероятностью, чем предыдущее. Пока я спал, мне пришло в голову довольно забавное решение на ту же тему. Оно быстрее примерно на 30%, не обладает ограничением на размер и точнее вычисляет вероятности (у Димы «трафка» не выпадает с вероятностью примерно 52%), но не решает задачу полностью. Кто скажет в чём разница, не запуская код?

for ($i = 5; $i && mt_rand(0, 1); --$i);
10 комментариев
Ramon (rembish.ru) 2007

У Вас веса в обратную сторону: пятерка выпадает чаще, чем ноль.
И, кроме того, у Вас правильно обрабатывается оставшийся вес — у Димы, например, туда отводится ~1,5625% у вас должные оставшиеся ~3,125%.

Евгений Степанищев (bolknote.ru) 2007

Второе — верно, но вы запускали, судя по всему, а это не так интересно. То, что всё идёт в обратную сторону решается реверсом цикла или вычитанием из пяти.

Ramon (rembish.ru) 2007

Вообще, и да, и нет. Я написал свой вариант через array_map/array_fill и уже там углядел, что проценты по идее теряются — оттуда возникла идея, которую визуально проверил на Вашем примере.

nudnik.ru 2007

Разница в том. что твое решение «не решает задачу полностью», geeze.

nudnik.ru 2007

У меня, кстати, в работающем коде стоит (1,63) вместо (0,64).

Но я побоялся, что люди не поймут, поэтому написал «более понятно».

Ramon (rembish.ru) 2007

stats_rand_gen_normal?

Евгений Степанищев (bolknote.ru) 2007

array_fill можно, да, но решение хотелось сделать неочевидным :)

Евгений Степанищев (bolknote.ru) 2007

Дим, конечно, мой пример задачу не решает, тут достоинства твоего очевидны :) Просто приснился забавный пример. Кстати говоря, вряд ли все могут сказать сходу как работает то и другое и почему результаты в «хвосте» разные :) И откуда взялись 2% — тоже :)

Ramon (rembish.ru) 2007

Вот, кстати, мой вариант: strpos(implode(«„, array_map(„mt_rand“, array_fill(0, 6, 0), array_fill(0, 6, 1))), „1“);

Евгений Степанищев (bolknote.ru) 2007

Мда, в каком-нибудь Perl или Ruby это было бы куда изящнее :)