为什么rand($ val)在$ val>时不会发出警告2 ** randbits?

时间:2014-03-31 21:31:28

标签: perl

我正在使用Strawberry Perl v5.16.2使用重复调用int rand 1_000_000来构建一些假数据。之后,我发现由于我的perl randbits=15,上面的表达式只会返回2**1532768个可能的值。

>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_0002.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"返回了以下有用的资源:

前者是讨论此问题所有不同方面的重要资源,并提供了randuse 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
  • 我是否安装了草莓Perl错误以达到如此低的randbits?有没有办法提高这个价值?用户是否有责任这样做?

感谢。

3 个答案:

答案 0 :(得分:0)

您是否看过CPAN似乎有一些适当的资源。对于非常大的数字,Math :: BigInt :: Random似乎很好。

答案 1 :(得分:0)

出于非加密目的,请使用Math::Random::MTThe 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的时间。

perl v5.20 - perldelta

开始
  
      
  • 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);等替代程序。