php 随机数rand,PHP随机数函数rand()与mt_rand() - 米扑博客

PHP 中 rand()与mt_rand()都是用于产生一个指定范围内单独随机数的函数,如果需要产生多个不重复的随机数,请参考:PHP生成指定范围内的N个不重复的随机数。

既然他们都是用于产生一个随机数,那么他们有什么区别呢?

rand() 函数默认使用 libc 随机数发生器,很多老的 libc 的随机数发生器具有一些不确定和未知的特性而且效率很低;

mt_rand() 则是用了 Mersenne Twister 中已知的特性作为随机数发生器,它产生随机数值的平均速度比 libc 提供的 rand() 快四倍。

所以,PHP 中 mt_rand()函数是非正式用来替换rand()的。

rand — 产生一个随机整数 (PHP 4, PHP 5, PHP 7)

rand ( void ) : int

rand ( int $min , int $max ) : int

参数

min    返回的最低值(默认:0)

max    返回的最高值(默认:getrandmax())

返回值   A pseudo random value between min (or 0) and max (or getrandmax(), inclusive)

如果没有提供可选参数 min 和 max,rand() 返回 0 到 getrandmax() 之间的伪随机整数。例如想要 5 到 15(包括 5 和 15)之间的随机数,用rand(5, 15)。

说明:在某些平台下(例如 Windows)getrandmax() 只有 32767。如果需要的范围大于 32767,那么指定 min 和 max 参数就可以生成更大的数了,或者考虑用 mt_rand() 来替代之。

mt_rand — 生成更好的随机数    (PHP 4, PHP 5, PHP 7)

mt_rand ( void ) : int

mt_rand ( int $min , int $max ) : int

参数

min    可选的、返回的最小值(默认:0)

max    可选的、返回的最大值(默认:mt_getrandmax())

返回值   返回 min (或者 0) 到 max (或者是到 mt_getrandmax() ,包含这个值)之间的随机整数。

很多老的 libc 的随机数发生器具有一些不确定和未知的特性而且很慢。PHP 的 rand() 函数默认使用 libc 随机数发生器。mt_rand() 函数是非正式用来替换它的。该函数用了 » Mersenne Twister 中已知的特性作为随机数发生器,它可以产生随机数值的平均速度比 libc 提供的 rand() 快四倍。

如果没有提供可选参数 min 和 max,mt_rand() 返回 0 到 mt_getrandmax() 之间的伪随机数。例如想要 5 到 15(包括 5 和 15)之间的随机数,用mt_rand(5, 15)。

总结

min, max 参数皆为可选,规定随机数产生的范围。

如果没有提供可选参数 min 和 max,则返回 0 到 RAND_MAX 之间的伪随机整数。

例如,想要 1 到 100(包括 1 和 100)之间的随机数,用 rand(1, 100) 或 mt_rand(1,100)。

mt_rand()是更好地随机数生成器(推荐使用),因为它跟rand()相比播下了一个更好地随机数种子;而且性能上比rand()快4倍,mt_getrandmax()所表示的数值范围也更大。

注: 自 PHP 4.2.0 起,PHP产生随机数都不再需要用 srand() 或 mt_srand() 函数产生随机种子,已经会自动完成。

PHP生成指定范围内的N个不重复的随机数

有时候需要生成指定范围内一定数量的不重复随机数,例如生成100个20位随机数,具体怎么设计这个生产随机数的函数呢?

方法1:可以将随机产生的数存入数组,并在存入的同时去除重复的值,即可生成一定数量的不重复随机数。

方法2:可以把指定范围内的数值存进数组,再使用shuffle($array)打乱这个数组,然后再截取其中一定数量的值。

说明:方法2的做法,在指定的随机数范围太大的时候会产生一个较大的数组。

下面给出第一种做法的代码,第二种做法更简单,大家可以尝试下

/**

* 生成一定数量的不重复随机数,指定的范围内整数的数量必须比要生成的随机数数量大

* https://mimvp.com in 2019.05.20

*

* @param string $min:指定随机数的最小值(包含)

* @param string $max:指定随机数的最大值(包含)

* @param string $num: 指定生成数量

* @return array $result: 返回指定数量的随机数结果数组

*

* array_flip() 函数返回一个反转后的数组,如果同一值出现了多次,则最后一个键名将作为它的值,所有其他的键名都将丢失

*/

function generate_unique_rand($min, $max, $num) {

$count = 0;

$result = array();

while ($count < $num) {

$result[] = mt_rand($min, $max);

// $result = array_flip(array_flip($result));// 通过两次反转让随机数唯一, 使用 array_unique 替代

$result = array_unique($result);// 返回唯一性元素的数组

$count = count($result);

}

shuffle($result);// shuffle() 函数把数组中的元素按随机顺序重新排列, 打乱数组重新赋予数组新的下标

return $result;

}

//生成10个1到100范围内的不重复随机数

$unique_rand_array = generate_unique_rand(10, 99, 10);// 10, 90, 91(极限测试,死循环)

sort($unique_rand_array);// 对返回的随机数排序, 方便查看

print( sprintf("
count: %d, unique_rand_array: %s", count($unique_rand_array), json_encode($unique_rand_array)) );

shuffle($unique_rand_array);// 对返回的随机数排序, 随机顺序重新排列

print( sprintf("
count: %d, unique_rand_array: %s", count($unique_rand_array), json_encode($unique_rand_array)) );

运行的结果:

count: 10, unique_rand_array: [11,34,37,45,72,79,85,87,90,96]

count: 10, unique_rand_array: [79,90,96,72,11,85,87,37,45,34]

说明:

1、生成随机数时我们用了 mt_rand() 函数。这个函数生成随机数的平均速度要比 rand() 快几倍。

2、去除数组中的重复值时用了“翻转法”,就是用 array_flip() 把数组的 key 和 value 交换两次,这种做法在去除数组重复值的同时效率也比用 array_unique() 快得多。

3、返回数组前,先使用 shuffle() 为数组赋予新的键名,保证键名是 0-n 连续的数字。如果不进行此步骤,可能在删除重复值时造成键名不连续,如果用for遍历的时候会有问题,但如果用foreach或不需要遍历的时候可以不需要shuffle。

mt_rand() 和 rand() 速度测试

测试代码

/**

* 功能: mt_rand() 和 rand() 速度测试

* 版权: https://mimvp.com

* 日期: 2019-05-20

*/

function microtime_float() {

list($usec, $sec) = explode(" ", microtime());

return ((float)$usec + (float)$sec);

}

print("
microtime_float(): " . microtime_float());

function test_rand_mtrand($count=10000) {

print("
count: $count");

// rand()

$time_start = microtime_float();

for($i=0; $i

{

rand();

}

$time_end = microtime_float();

$time_cost = $time_end - $time_start;

echo "
rand() time_cost ---------- $time_cost seconds";

// mt_rand()

$time_start = microtime_float();

for($i=0; $i

{

mt_rand();

}

$time_end = microtime_float();

$time_cost = $time_end - $time_start;

echo "
mt_rand() time_cost ----- $time_cost seconds";

}

test_rand_mtrand(1000);// 1千次

test_rand_mtrand(10000);// 1万次

test_rand_mtrand(100000);// 10万次

test_rand_mtrand(1000000);// 100万次

test_rand_mtrand(10000000);// 1000万次(耗时较长)

?>

运行结果:

microtime_float(): 1559201781.7574

count: 1000

rand() time_cost ---------- 0.00091695785522461 seconds

mt_rand() time_cost ----- 0.00093388557434082 seconds

count: 10000

rand() time_cost ---------- 0.008936882019043 seconds

mt_rand() time_cost ----- 0.010462999343872 seconds

count: 100000

rand() time_cost ---------- 0.076805114746094 seconds

mt_rand() time_cost ----- 0.074769020080566 seconds

count: 1000000

rand() time_cost ---------- 0.857342004776 seconds

mt_rand() time_cost ----- 0.76551508903503 seconds

count: 10000000

rand() time_cost ---------- 7.561311006546 seconds

mt_rand() time_cost ----- 7.7968890666962 seconds

结论:两者的循环效率实际上差不多,没有传说中的相差4倍

参考推荐:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值