#!/usr/bin/perl -w
use strict;

=pod

FROM PERLFAQ4

   Computers are good at being predictable and bad at being random (despite
   appearances caused by bugs in your programs :-).

   http://www.perl.com/CPAN/doc/FMTEYEWTK/random , courtesy of Tom Phoenix,
   talks more about this.

   John von Neumann said,
      "Anyone who attempts to generate random numbers by deterministic means
       is, of course, living in a state of sin."

   If you want numbers that are more random than rand with srand provides, you
   should also check out the Math::TrulyRandom module from CPAN. It uses the
   imperfections in your system's timer to generate random numbers, but takes
   this quite a while. If you want a better pseudorandom generator than comes
   with your operating system, look at "Numerical Recipes in C" at
   http://www.nr.com/


EXPLANATION OF KEY VARIABLES USED BELOW
$size        = desired size of the newly generated output array

@randed      = the array we're going to generate, randomize, and return

$bignums     = use this number as a divisor to split up huge numbers into
                 C longs that are small enough to be handled by your system
                 architecture and/or Perl binary (depending on how compiled)
                 You really shouldn't need to mess with this unless you start
                 fooling around with insanely titanic numbers.  Setting this
                 too low will decrease the entropy acheived per pass and
                 requiring more passes to generate a randomized array.  The
                 array will also be less randomized.

=cut

my($started)   = time;
my($size)      = $ARGV[0] || die(q[C'mon man! Gimme an array size!]);
my($bignums)   = $ARGV[1] || 256; # put bignum def right here.
my($splits)    = sprintf('%.0f',$size / $bignums);
my(@randed)    = ();

if ($bignums && $size > $bignums) {

   my($split)  = 0;

   for (my($i) = 1; $i <= $size; $i += $bignums) {

      print
         (
            qq[looping over split @{[++$split]} of $splits...],
            qq[\n] x 2
         );

      my($endchunk) = ($bignums + $i > $size) ? $size : ($bignums + $i) - 1;

      splice
         (
            @randed,
            eval { (scalar(@randed)) ? rand(scalar(@randed)) : 0 },
            0,
            &randomize($i .. $endchunk)
         )
   }
}
else {

   push( @randed, &randomize(1 .. $size))
}

sub randomize {

   my(@gen)    = @_;
   my($len)    = scalar(@gen);
   my($seq)    = 1;
   my($ii)     = 0;

   # make as many passes over @gen as it takes to get it 100% randomized
   while ($seq > 0) {

      # make one pass over @gen
      for ( my($iii) = 0; $iii <= $len; $iii++ ) {

         my($randelem) =
            splice
               (
                  @gen,
                  rand($len),
                  1,
               );

         @gen = ( $randelem, @gen );
      }

      # figure out how much entropy occurred in @gen during this pass
      my($iseq) = 0; for ( my($iv) = 0; $iv < ($len - 1); $iv++ ) {

         ++$iseq if ( $gen[ $iv+1 ] - $gen[ $iv ] == 1)
      }

      $seq = $iseq;

      # report
      print(<<__pass__); ++$ii
   After @{[ $ii+1 ]} passes, present \@randed chunk is \%@{[
   100 - (($iseq / $len) * 100) ]} (size @{[ scalar(@gen) ]}) percent random-ed

__pass__
   }

   return(@gen);
}


print(<<__final__);
---------
   randomized array contains @{[ scalar(@randed) ]} elements:

__final__


print(shift(@randed), qq[\n]) while (@randed);

print(<<__took__) and exit;

took @{[ (time - $started) / 10 ]} seconds

__took__


=pod

   AUTHOR
        -Tommy Butler, professional contractor and open source proponent

         Atrixnet™, for Internet Business Software®
            http://atrixnet.com
            6711 Forest Park Dr
            Arlington, TX
                 76001

   COPYRIGHT
         Copyright Tommy Butler. All rights reserved

   BUGS
      Please report any bugs to me

=cut