Pers.narod.ru. PHP. Генерация случайных чисел на PHP |
На стареньком уже PHP 4.3.1 большую часть дня писал скрипт. В коде имелись 2 функции, назначение которых - генерация случайных чисел в заданных диапазонах. Вот начальный код:
function select_random_items ($k,$arr) { //выбрать $k случайных элементов из массива $arr $c=count($arr); if ($k>$c) $k=$c; if ($k==$c) return $arr; $a = array (); //Начиная с PHP 4.2.0 эта строка будет только мешать! srand (time()); for ($i=0; $i<$k; ) { $n=rand (0,$c-1); if (!in_array($arr[$n],$a)) { array_push ($a,$arr[$n]); $i++; } } return $a; } function random_numbers ($kol,$all) { //вернет массив из $kol случ. чисел в диапазоне [0,$all-1] if ($kol>$all) $kol=$all; $a = array (); //Начиная с PHP 4.2.0 эта строка будет только мешать! srand (time()); for ($i=0; $i<$kol; ) { $n=rand (0,$all-1); if (!in_array($n,$a)) { array_push ($a,$n); $i++; } } return $a; }
Обратите внимание на закомментаренную строку, "которая будет только мешать".
Как честный человек, я привык инициализировать генератор случайных чисел перед его использованием (вызов srand).
В свою очередь, обе эти функции вызывались в цикле, чтоб сформировать некий массив номеров.
Проблемы начались, когда я обнаружил, что цепочки чисел получаются слишком уж предсказуемыми - а так как числа эти представляли собой номера вопросов теста, допускать такого было нельзя.
После пары часов тестирования в разных режимах ответ нашелся в доке по PHP: srand: Since PHP 4.2.0 it's no longer necessary to seed the random number generator before using it. (начиная с версии PHP 4.2.0 больше нет необходимости вызывать эту функцию).
В доке сказано еще мягко. На быстродействующем современном компе при частом вызове функций, зависящих от srand, результаты могут быть просто ужасными.
С другой стороны, скрипт может понадобиться запускать и в более старых версиях PHP. Универсальный выход - делать вызов srand или ее аналога mt_srand из кода, выполняемого только единожды при старте системы, например, так:
<?php session_start(); if (!isset($_SESSION['random_init'])) { //Инициализировать генератор с.ч. только 1 раз! //С версии PHP 4.2.0 инициализация может только мешать генерации нормальных цепочек! mt_srand( (double) microtime() * 1000000); $_SESSION['random_init']='1'; } ?>
Можно обойтись и без сессий:
<?php function init() { static $random_init; if (empty($random_init)) { mt_srand ((double)microtime() * 1000000); $random_init=1; } } //... init(); //Только первый вызов init сделает ms_rand init(); ?>
гостевая; E-mail |