0

请看下面这段代码:

srand(localtime);

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

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

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

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

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

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

4

2 回答 2

7

尝试使用use strictand运行它use 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 ^ $$or time ^ ($$ + ($$ << 15))),但这不再是必需的了。

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

于 2012-06-21T11:05:35.700 回答
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();
于 2012-06-21T13:39:58.020 回答