Разница между mt rand() и rand()


В чем разница между использованием mt_rand($min, $max) и rand($min, $max) в отношении скорости?

Author: Thomas Rbt, 2015-02-27

6 answers

Обновление

Начиная с PHP 7.1 mt_rand полностью заменил rand, и rand был сделан псевдонимом для mt_rand. В приведенном ниже ответе основное внимание уделяется различиям между двумя функциями для более старых версий и причинам введения mt_rand.


Скорость не была причиной введения mt_rand!

Функция rand существовала задолго до mt_rand, но она была глубоко ошибочной. PRNG должен получить некоторую энтропию, число, из которого он генерирует последовательность случайных чисел. Если ты распечатайте список из десяти чисел, которые были сгенерированы rand() примерно так:

for ($i=0;$i<10;++$i)
    echo rand(), PHP_EOL;

Выходные данные можно использовать для определения того, каким было начальное значение rand, и с его помощью вы можете предсказать следующие случайные числа. Есть инструменты, которые делают это, так что погуглите немного и протестируйте это.

Также существует проблема с rand относительно быстрым отображением шаблонов в его случайных числах , как показано здесь. Проблема mt_rand, похоже, тоже решается намного лучше.

mt_rand использует лучший алгоритм рандомизации (поворот Мерсенна), который требует, чтобы было известно больше случайных чисел, прежде чем можно будет определить начальное значение и быстрее. Это не означает, что mt_rand по определению быстрее, чем rand, это означает только то, что способ генерации чисел выполняется быстрее и, по-видимому, не оказывает реального влияния на производительность функции, как показали другие ответы здесь.
В любом случае, взгляните на mt_srand и srand документы. Я уверен, что они будут содержать дополнительную информацию

Если алгоритм mt_rand приводит к увеличению производительности, то это здорово для вас, но это счастливое совпадение. TL;TR:

mt_rand был введен для устранения проблем, существующих в rand!

 40
Author: Elias Van Ootegem, 2017-01-09 13:57:25

Обновление (PHP 7.1):

rand() и srand() теперь стали псевдонимами mt_rand() и mt_srand() соответственно. Это означает, что выходные данные для следующих функций претерпели изменения: rand(), shuffle(), str_shuffle(), и array_rand().

Это означает, что начиная с версии 7.1 между ними обоими нет практической разницы, потому что rand внутренние вызовы mt_rand.


До PHP 7.1:

Использование rand() не является плохой практикой, если это не используемый в целях безопасности, я обычно использую rand() (привычка?).

Если вам нужно огромное количество случайных чисел, вам понадобится mt_rand вместо этого rand. mt_rand имеет период 219937 - 1, намного лучше, чем rand (232). Взгляните на эту статью о генерации графических шаблонов с использованием rand и mt_rand.

Периодичность и энтропия являются единственными причинами использования mt_rand() вместо rand(), а не безопасность или скорость улучшения.

Математически mt_rand имеют большую энтропию и большую периодичность, чем rand (219937-1 против 232).

Если вам нужно несколько случайных чисел, и безопасность не является проблемой, rand выполнит эту работу (получите случайное число, чтобы решить, запускать ли процесс очистки).


Повышение скорости тестирования

На практике между этими двумя функциями нет большой разницы в скорости (возможно, потому, что PHP⇔C накладные расходы на обертку?).

Тестовый код PHP:

<?php
for ($c = 0; $c < 3; $c++) {
  $start = microtime(true);
  $sum = 0.0;
  for ($i = 0; $i < 100000000; $i++) {
    $sum += rand();
  }
  printf('[rand %d] Time: %.3f s%s', $c, microtime(true) - $start, PHP_EOL);
}
for ($c = 0; $c < 3; $c++) {
  $start = microtime(true);
  $sum = 0.0;
  for ($i = 0; $i < 100000000; $i++) {
    $sum += mt_rand();
  }
  printf('[mt_rand %d] Time: %.3f s%s', $c, microtime(true) - $start, PHP_EOL);
}

Тесты на PHP 7.0.19:

$ php timing.php
[rand 0] Time: 4.658 s
[rand 1] Time: 4.664 s
[rand 2] Time: 4.654 s
[mt_rand 0] Time: 4.267 s
[mt_rand 1] Time: 4.255 s
[mt_rand 2] Time: 4.261 s

Тесты в PHP 5.4.45 (более медленная машина):

$ php timing.php
[rand 0] Time: 10.862 s
[rand 1] Time: 10.889 s
[rand 2] Time: 10.615 s
[mt_rand 0] Time: 10.948 s
[mt_rand 1] Time: 9.883 s
[mt_rand 2] Time: 10.190 s

Только 6-9%, а не 400%, как утверждалось.


Использование в целях безопасности

Но если вашему приложению требуется много энтропии из-за проблем с безопасностью, вам понадобится более безопасный способ и openssl_random_pseudo_bytes() возможно, это лучшее решение, работает ли оно (намного лучше, но медленнее? мы нужна безопасность, а не скорость?) опираясь на проблемы, связанные с openssl.

Ни то, ни другое rand() ни mt_rand() достаточно безопасны:

Внимание Эта функция не генерирует криптографически защищенные значения и не должна использоваться в криптографических целях. Если вам нужно криптографически защищенное значение, рассмотрите возможность использования random_int(), random_bytes(), или openssl_random_pseudo_bytes() вместо этого.

Существуют расширения PHP, такие как random_compat, но я этого не сделал рекомендую использовать их, если в этом нет необходимости.

 19
Author: OscarGarcia, 2017-05-30 07:22:06

Руководство по PHP по mt_rand() заявляет, что это:

, который будет генерировать случайные числа в четыре раза быстрее, чем обеспечивает средний libc rand().

 1
Author: Forien, 2015-02-27 09:09:38

Начиная с PHP 7.1, нет никакой разницы. rand() теперь является псевдонимом для mt_rand().

См. http://php.net/manual/en/migration71.incompatible.php#migration71.incompatible.rand-srand-aliases

И более подробная информация: https://wiki.php.net/rfc/rng_fixes

 1
Author: Bell, 2016-12-14 05:46:05


Ниже приведена разница в скорости для них обоих :-
mt_rand($min, $max) является в четыре раза быстрее по сравнению с rand($min, $max)

Причина в том, что rand($min, $max) использует генератор случайных чисел libc, в то время как mt_rand($min, $max) использует Твистер Мерсенна, который в четыре раза быстрее.

Надеюсь, это разрешит ваши сомнения.
Спасибо.

 -1
Author: PHP Team, 2015-02-27 08:45:43

Они кажутся равными по скорости:

function timeit($times, $func) {
    $t = microtime(1);
    while($times--) $func();
    return microtime(1) - $t;
}

echo PHP_OS, " ", phpversion(), "\n";
echo timeit(100000, function() {    rand(0,1000); }), "\n";
echo timeit(100000, function() { mt_rand(0,1000); }), "\n";

Результаты для OSX Mavericks и VirtualBox'ed Ubuntu 11:

Darwin 5.5.19
0.038038969039917
0.033117055892944

Linux 5.3.6-13ubuntu3.10
0.031459093093872
0.031935214996338

Если эти меры верны, комментарий руководства, упомянутый в другом месте, следует считать неправильным/устаревшим.

 -1
Author: georg, 2015-02-27 08:52:58