我使用Strawberry Perl v5.16.2来构造一些假数据,使用对int rand 1_000_000的重复调用。经过相当多的混乱之后,我发现由于我的perl的randbits=15,上面的表达式只返回2**15或32768可能的值。
>perl -V:randbits
randbits='15';我的问题是:
rand $val where $val > 2 ** randbits时,为什么$val > 2 ** randbits不返回警告perldoc rand根本不提这个问题?有一个关于如何"rand() is not cryptographically secure"的增编。我认为,这也值得一份增编,其中也提出了建议的替代解决办法。设置
我试图创建一些假数据来测试一种算法,用于对平均20个重复的大量数据进行排序。这对1,000和10,000个条目都有效,但当我跳到1,000,000时,我发现我丢失了很多独特的值。
这似乎是一种统计上的不可能。在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"做一个快速的Googlefor"perl rand does maximum 32768 integers"返回了以下有用的资源:
What is wrong with perl's antique random number generatorHow big can the argument to Perl's rand be? - Stack Overflow前者是讨论这个问题的所有不同方面的一个很好的资源,并提供了用use Math::Random::MT qw(rand);和use Math::Random::MT::Auto qw(rand);代替use Math::Random::MT 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。谢谢。
发布于 2014-06-13 19:37:43
是时候升级perl了。
rand现在使用一致的随机数生成器。
以前,perl将使用特定于平台的随机数生成器,在libc ()、随机()或drand48()之间变化。
这意味着perl的随机数的质量将因平台而异,从Windows上的15位rand()到POSIX平台上的48位,比如Linux和drand48()。
Perl现在在所有平台上使用自己的内部drand48()实现。这并不能使perl的rand加密安全。perl #115928我仍然希望,当rand的值大于2 ** randbits时,旧版本的perl会发出警告,但这是我所希望得到的最好的结果。
如果其他程序员无法升级的话,他们仍然需要警惕其他程序员,并继续推荐其他的选择,比如use Math::Random::MT qw(rand);。
发布于 2014-03-31 22:06:19
您看过CPAN了吗,似乎有一些合适的资源。数学::BigInt::对于非常大的数字来说,随机似乎是一个很好的选择。
发布于 2014-04-02 02:58:14
对于非加密目的,请使用数学::随机::。Mersenne Twister PRNG具有很好的特性。
您可以使用函数接口替换rand内置的内容:
面向功能的接口:
use Math::Random::MT qw(srand rand irand);
# now use srand() and rand() as you usually do in Perlhttps://stackoverflow.com/questions/22772578
复制相似问题