请查看以下代码:
srand(localtime);
for (my $ik = 0; $ik < 3; $ik += 1)
{
print int(rand(10)),"\n";
sleep(1);
}
我在中间有足够的时间(5-10秒)多次调用上面的代码,但输出顺序仍然相同。
由于我已将种子设置为localtime
,因此每个调用必须使用不同的种子,并且可能会因时间间隔而生成不同的三个数字序列。为什么我一次又一次地得到相同的序列。
注意:代码不在循环中,它位于多次执行的Perl文件中。
文档说如果多个实例在相同的“秒”中运行导致同一个种子,则此种子会失败 - 在这种情况下并非如此。
编辑:: @simbabque的解决方案确实有所帮助,但未获得预期的随机性。请看下面对上述解决方案的评论。
答案 0 :(得分:7)
尝试使用use strict
和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 ^ $$
或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();