在php里编写自己的随机数发生器


前段时间找工作面试,笔试到一道题目:

自己实现php里的mt_rand()函数。

想了一下,做了如下回答:

<?php

function mt_rand_test($min, $max){
    $gap = $max - $min + 1;
    return $min + time()%$gap;
}

echo mt_rand_test(1, 100);

利用高值($max)和低值($min)取时间戳的模再加上低值,这样就能获得低值和高值之间的随机数。 怎么样,感觉这个答案还行吧?

其实是错的,因为time()函数返回的时间戳每一秒才会变一次…… 也就是说返回的随机数一秒内都是一样的, 是周期性的伪随机数 ,而且周期很小。

在加大周期以后,才会有非周期性随机数函数效果。

怎么加大周期呢,秒不够,微秒(百万分之一秒)顶上:

<?php

function mt_rand_test1($min, $max){
    $gap = $max - $min + 1;
    list($usec, $sec) = explode(' ', microtime(false));
    //注意微秒小数点之后是8位,8位的末两位总是0,需要去掉,否则在$gap等于100的时候在同一秒时间内取的模总是不变的
    $usec = substr($usec, 2, 6);
    return $min + ($usec+$sec) % $gap;
}

echo mt_rand_test1(1, 100);

接下来写一个测试函数分别(因为cycle_show()里的$cycle是静态变量)对上面两个函数进行对比:

<?php

function cycle_show($k){
    static $cycle = array();

    if (isset($cycle[$k])){
        $cycle[$k] += 1;
    } else {
        $cycle[$k] = 1;
    }
    return $cycle;
}

周期小的随机数函数mt_rand_test()

<?php

foreach (range(1, 10000) as $v){
    $a = cycle_show(mt_rand_test(1, 100));
    if ($v == 10000){
        ksort($a);
        print_r($a);
    }
}

输出结果:

Array
(
    [12] => 10000
)

周期较大的随机数函数mt_rand_test1()

<?php

foreach (range(1, 10000) as $v){
    $a = cycle_show(mt_rand_test1(1, 100));
    if ($v == 10000){
        ksort($a);
        print_r($a);
    }
}

输出结果:

Array
(
    [1] => 109
    [2] => 89
    [3] => 108
    [4] => 92
    [5] => 91
    [6] => 98
    [7] => 99
    [8] => 113
    .
    .
    .
    [95] => 96
    [96] => 103
    [97] => 95
    [98] => 101
    [99] => 107
    [100] => 113
)

所以,在周期拉大以后,随机性会更明显一点,尽管它还是周期性随机数函数。

Published

Author

levin

Category

Program language

Tags

PHP
Disqus loading now...