我正在使用Strawberry Perl
v5.16.2
使用重复调用int rand 1_000_000
来构建一些假数据。之后,我发现由于我的perl randbits=15
,上面的表达式只会返回2**15
或32768
个可能的值。
>perl -V:randbits
randbits='15';
我的问题是:
rand $val
使用$val > 2 ** randbits
时,为什么use warnings;
不会返回警告?perldoc rand
根本没有提到这个问题?关于如何"rand() is not cryptographically secure"
有一个附录。我相信这也值得提出补充建议的替代解决方案。设置
我正在尝试创建一些虚假数据来测试用于对大量数据进行排序的算法,平均重复20次。这适用于1,000和10,000个条目,但是当我跳到100万时,我发现我缺少很多独特的值。
这似乎是统计上的不可能性。不会在2000万次拉动中选择小于100万的特定整数的概率p
为(999_999/1_000_000) ** 20_000_000
或2.06e-9
。因此,不选择任何整数的概率为.2%
。
我很快将另一个脚本黑客攻击,以确认我的假数据生成器中没有缺陷:
use strict;
use warnings;
use List::Util qw(sum max min);
our $max_count = 1_000;
my %count;
while (1) {
my $val = int rand 1_000_000;
last if ++$count{$val} > $max_count;
}
my $sum = sum values %count;
my $max = max values %count;
my $min = min values %count;
my $count = scalar keys %count;
print "$sum interations. $count integers of expected 1mil with min $min, max $max\n";
输出:
28,958,579 interations. 32768 integers of expected 1mil with min 772, max 1001
显然,32,768
是一个巨大的红旗,是2
的强大力量,所以快速谷歌"perl rand does maximum 32768 integers"
返回了以下有用的资源:
What is wrong with perl's antique random number generator
How big can the argument to Perl's rand be? - Stack Overflow
前者是讨论此问题所有不同方面的重要资源,并提供了rand
与use Math::Random::MT qw(rand);
和use Math::Random::MT::Auto qw(rand);
的替换。
SO帖子提供了an answer
,其中包含一个不需要安装新模块的解决方案,只需调用rand
两次以获得更多位。
use Config;
use constant RANDBITS => $Config{randbits};
use constant RAND_MAX => 2**RANDBITS;
sub double_rand {
my $max = shift || 1;
my $iv =
int rand(RAND_MAX) << RANDBITS
| int rand(RAND_MAX);
return $max * ($iv / 2**(2*RANDBITS));
}
幸运的是,这两个问题都解决了我最初的问题。回顾一下,我很好奇......
rand
是否有更好的下降?perldoc rand
提到这个问题,为什么没有两句增编?warnings
没有警告大于2**randbits
的值?如果有人想忽略这些警告,可能会有no warnings 'rand'
来电或只是调用没有价值的rand:val * rand
。感谢。
答案 0 :(得分:0)
您是否看过CPAN似乎有一些适当的资源。对于非常大的数字,Math :: BigInt :: Random似乎很好。
答案 1 :(得分:0)
出于非加密目的,请使用Math::Random::MT。 The Mersenne Twister PRNG有很好的属性。
您可以使用功能界面替代rand
内置:
use Math::Random::MT qw(srand rand irand);
# now use srand() and rand() as you usually do in Perl
答案 2 :(得分:0)
升级perl的时间。
开始
rand
现在使用一致的随机数生成器以前perl会使用特定于平台的随机数生成器,在libc rand(),random()或drand48()之间变化。
这意味着perl随机数的质量会因平台而异,从Windows上的15位rand()到POSIX平台上的48位,如带有drand48()的Linux。
Perl现在在所有平台上都使用自己的内部drand48()实现。这并不会使perl的
rand
加密安全。 [perl#115928]
我仍然希望旧版本的perl会在值大于rand
时使用2 ** randbits
时发出警告,但这是我希望的最好结果。
仍然需要注意Windows上的其他程序员,如果他们无法升级,请继续推荐use Math::Random::MT qw(rand);
等替代程序。