Подскажите плиз, может кто сталкивался. Есть задача : надо сгенерить одну случайную область чисел, а потом на основе ее сгенерить вторую. Первая должна содержать вторую. Причем в целях экономии ресурсов нельзя пользоваться массивами, переменными и т.п.. Т.е. первую область сохранить нельзя.
Для начала проведем небольшой ликбез.
Не существует алгоритмов, способных генерировать последовательность случайных чисел (СЧ), т.к. любой алгоритм детерминирован по определению.
Любой алгоритмический генератор "случайных" (на самом деле псевдослучайных) чисел (ГСЧ) можно представить в виде детерминированного конечного автомата (ДКА). Это означает, что значение очередного "случайного" числа является функцией от текущего состояния ДКА и его входных параметров. Обычно в данных генераторах входные параметры не используются.
Из вышесказанного следует, что любая последовательность, полученная с помощью алгоритмического генератора СЧ, является периодической, т.к. любой ДКА обладает конечным набором состояний.
Плавно переходим от лирики к физике.
Функция [m]srand[/m] не генерирует псевдослучайную последовательность. Она всего лишь устанавливает начальное состояние ДКА. Функция [m]rand[/m] переводит ДКА в следующиее состояние и возвращает его выходное значение.
А теперь, собственно, ответ на поставленный вопрос.
Любой алгоритмический ГСЧ можно представить не только в виде ДКА, но и функции, зависящей от двух параметров - начального вектора инициализации
IV (начальное состояние ДКА) и порядкового номера
N числа в последовательности. Тогда очевидно решение поставленной задачи:
- "случайность" последовательности задается с помощью
IV. Для его генерации можно использовать, например, функцию [m]microtime[/m].
- первая последовательность генерируется в цикле
Код:
for (i=0; i<N1; i++) rnd_num = f(IV, i);
где N1 - количество чисел, которые нужно сгенерировать в первой последовательности;
f() - функция ГСЧ;
- вторая последовательность генерируется в цикле
Код:
for (i=0; i<N2; i++) rnd_num = f(IV, rand() % N1);
где N2 - количество чисел, которые нужно сгенерировать во второй последовательности. Очевидно, что все числа из второй последовательности будут принадлежать первой последовательности. И не нужно использовать никаких массивов для хранения первой последовательности.
Главная проблема - создать функцию ГСЧ f(). В задачах, где безопасность не является критическим фактором, можно воспользоваться любой хэш-функцией в качестве f(). Например, функцией [m]crc32[/m], которая вычисляется весьма быстро:
PHP:
function f($iv, $n)
{
return crc32($iv . $n);
}
Функцией [m]crc32[/m] не рекомендуется пользоваться в приложениях, где важна безопасность, т.к. при ее использовании сравнительно легко найти корреляцию между выходом данной функции и значением $n при неизвестном $iv, либо даже вычислить $iv по набору выходных значений. В этом случае лучше заменить [m]crc32[/m] на криптографически стойкую хэш-функцию. Например, на [m]md5[/m] или [m]sha1[/m]. Но в этом случае резко падает производительность ГСЧ, т.к. данные функции спроектированы таким образом, чтобы тратить сравнительно большое количество тактов процессора на их вычисление (в сотни тысяч раз больше, нежели для [m]crc32[/m]). Это необходимо для уменьшения вероятности успешной brute-force атаки на хэши, полученные с помощью данных функций.