|
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();
?>
|
|