Math-Prime-Util

 view release on metacpan or  search on metacpan

t/34-random.t  view on Meta::CPAN

#!/usr/bin/env perl
use strict;
use warnings;

use Test::More;
use Math::Prime::Util qw/irand irand64 drand urandomb urandomm
                         random_bytes entropy_bytes
                         srand csrand
                         mulmod addmod vecmin vecmax vecall/;

my $use64 = (~0 > 4294967295);
my $extra = defined $ENV{EXTENDED_TESTING} && $ENV{EXTENDED_TESTING};
my $maxbits = $use64 ? 64 : 32;

my $samples = $extra ? 100000 :  10000;

plan tests => 1
            + 2
            + 2
            + 2
            + 5  # drand range
            + 4  # identify rng and test srand/csrand
            + 4  # 0 / undef arguments to urandom*
            + 1  # urandomb
            + 3  # urandomm
            + 4  # entropy_bytes
            + 0;

########

ok( Math::Prime::Util::_is_csprng_well_seeded(), "CSPRNG is being seeded properly" );

########

{
  my @s = map { irand } 1 .. $samples;
  is( scalar(grep { $_ > 4294967295 } @s), 0, "irand values are 32-bit" );
  is( scalar(grep { $_ != int($_) } @s), 0, "irand values are integers" );
}

########

SKIP: {
  skip "Skipping irand64 on 32-bit Perl", 2 if !$use64;
  my $bits_on  = 0;
  my $bits_off = 0;
  my $iter = 0;
  for (1 .. 6400) {
    $iter++;
    my $v = irand64;
    $bits_on |= $v;
    $bits_off |= (~$v);
    last if ~$bits_on == 0 && ~$bits_off == 0;
  }
  is( ~$bits_on,  0, "irand64 all bits on in $iter iterations" );
  is( ~$bits_off, 0, "irand64 all bits off in $iter iterations" );
}

########

# This is really brute force, but it doesn't take too long.
{
  my $mask = 0;
  my $v;
  for (1..1024) {
    $v = drand;
    last if $v >= 1;
    next if $v < .5;
    for my $b (0..127) {
      last unless $v;
      $v *= 2;
      if ($v >= 1) {
        $mask |= (1 << $b);
        $v -= 1;
      }
    }
  }
  ok($v < 1, "drand values between 0 and 1-eps");
  my $k = 0; while ($mask) { $k++; $mask >>= 1; }
  # Assuming drand is working properly:
  #   k = 24   NV is float
  #   k = 53   NV is double
  #   k = 64   NV is long double
  # If we used drand48 we'd get 48 with double or long double.
  ok($k >= 21, "drand supplies at least 21 bits (got $k)");
}

sub check_float_range {
  my($name, $lo, $hi, $v) = @_;
  if ($lo <= $hi) {
    ok( vecall(sub{ $_ >= $lo && $_ < $hi },@$v), "$name: all in range [$lo,$hi)" );
  } else {
    ok( vecall(sub{ $_ >= $hi && $_ < $lo },@$v), "$name: all in range ($hi,$lo]" );
  }
}
my $num = $extra ? 1000 : 100;
check_float_range('drand(10)',0,10,[map{ drand(10) } 1..$num]);
check_float_range('drand()',0,1,[map{ drand() } 1..$num]);
check_float_range('drand(-10)',0,-10,[map{ drand(-10) } 1..$num]);
check_float_range('drand(0)',0,1,[map{ drand(0) } 1..$num]);
{
  # Skip warnings these give, worry about the behavior
  no warnings;
  check_float_range('drand(undef)',0,1,[map{ drand(undef) } 1..$num]);
}
# We can't easily supress the warning here, but we'd like to check the
# result.  Math::Random::Secure fails this, for instance.
#check_float_range('drand("foo")',0,1,[map{ drand("foo") } 1..$num]);

########

my $core_rand = "not drand48";
if (1) {
  my @r = map { CORE::rand() } 0..8;
  if (try_lcg(25214903917,11,2**48,@r)) {
    $core_rand = "drand48 (yech)";



( run in 0.528 second using v1.01-cache-2.11-cpan-71847e10f99 )