Perl的rand()函数以localtime作为种子

时间:2012-06-21 10:58:56

标签: perl random random-seed

请查看以下代码:

srand(localtime);

for (my $ik = 0; $ik < 3; $ik += 1)
{
    print int(rand(10)),"\n";
    sleep(1);
}

我在中间有足够的时间(5-10秒)多次调用上面的代码,但输出顺序仍然相同。

由于我已将种子设置为localtime,因此每个调用必须使用不同的种子,并且可能会因时间间隔而生成不同的三个数字序列。为什么我一次又一次地得到相同的序列。

注意:代码不在循环中,它位于多次执行的Perl文件中。

文档说如果多个实例在相同的“秒”中运行导致同一个种子,则此种子会失败 - 在这种情况下并非如此。

编辑:: @simbabque的解决方案确实有所帮助,但未获得预期的随机性。请看下面对上述解决方案的评论。

2 个答案:

答案 0 :(得分:7)

尝试使用use strictuse warnings运行此功能。它会给你:

Argument "Thu Jun 21 13:04:41 2012" isn't numeric in srand at ...

正确的是你的问题。 localtime在标量上下文中返回一个字符串。请尝试使用time,它将unix时间戳作为整数返回。 srand需要一个数值才能工作。

如果您向其添加Data::Dumper,则会看到代码中的种子始终为1

no strict; no warnings;
use Data::Dumper;
print Dumper srand(localtime);

for (my $ik = 0; $ik < 3; $ik += 1)
{
    print int(rand(10)),"\n";
    sleep(1);
}

表示:

$VAR1 = 1;
0
2
6

您需要的是:

use strict; use warnings;
srand(time);
for (my $ik = 0; $ik < 3; $ik += 1)
{
    print int(rand(10)),"\n";
    sleep(1);
}

修改

如果您想要良好的随机性,这仍然不是一个好主意。医生说:

  

在5.004之前的Perl版本中,默认种子只是   当前时间。这不是一个特别好的种子,这么多老   程序提供自己的种子值(通常为time ^ $$time ^ ($$ + ($$ << 15))),但这不再是必要的。

我建议您完全省略对srand的调用,除非您确实需要可重复的结果(即用于测试)。

答案 1 :(得分:0)

一般来说,没有理由通过反复播种PRNG来期望更好的随机性。

您可以使用以下脚本检查原始问题的原因:

#!/usr/bin/env perl

use strict; use warnings;
use 5.014;

for (1 .. 3) {
    my $seq = newseq(3, 5);
    printf "Seed = %s\n", $seq->{seed};
    my $it = $seq->{generator};
    while (defined(my $r = $it->())) {
        print "$r\n";
    }
    sleep 5;
}


sub newseq {
    my ($length, $limit) = @_;
    $length //= 10;
    $limit  //= 10;

    my $seed = srand(time);
    return {
        seed => $seed,
        generator => sub {
            return unless $length-- > 0;
            return rand($limit);
        },
    };
}

但是,如果确实需要统计独立的生成器,可以使用Math::Random::MT::Auto并创建单独的PRNG对象:

#!/usr/bin/env perl

use strict; use warnings;
use 5.014;

use strict;
use warnings;
use Math::Random::MT::Auto qw(:!auto);

my $prng1 = Math::Random::MT::Auto->new(SOURCE => '/dev/random');
my $prng2 = Math::Random::MT::Auto->new(SOURCE => 'random_org');

say $prng1->rand();
say $prng2->irand();