|
#
|
|
# Math::TT800 A perl5 implementation of Matsumoto's tt800 PRNG.
|
|
#
|
|
=head1 NAME
|
|
Math::TT800 - Matsumoto's TT800 Pseudorandom number generator
|
|
=head1 DESCRIPTION
|
|
This perl module implements M. Matsumoto's twisted generalized
|
|
shift register generator called TT800 as described in his article
|
|
published in ACM Transactions on Modelling and Computer Simulation,
|
|
Vol. 4, No. 3, 1994, pages 254-266.
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
use Math::TT800;
|
|
|
|
my $tt = new Math::TT800;
|
|
|
|
$tt->initialize( @seeds );
|
|
|
|
$value = $tt->next();
|
|
|
|
$ivalue = $tt->next_int();
|
|
|
|
=head1 FUNCTIONS
|
|
=over 4
|
|
=item new
|
|
my $tt = new Math::TT800;
|
|
my $tt = new Math::TT800 @seeds;
|
|
|
|
Create a new TT800 object. Providing seeds is optional.
|
|
|
|
=item initialize
|
|
|
|
$tt->initialize( @seeds );
|
|
|
|
This method initializes and (optionally) seeds a TT800 generator objec\
|
|
t.
|
|
A TT800 takes 25 integers as seed which must not be all zero.
|
|
If less than 25 integers are supplied, the rest are taken from the
|
|
default seed.
|
|
=item next
|
|
$value = $tt->next();
|
|
next returns the next pseudorandom number from the TT800 object as
|
|
a floating point value in the range [0,1).
|
|
|
|
=item next_int
|
|
|
|
$ivalue = $tt->next_int();
|
|
|
|
next_int returns a integer value filled with 32 random bits.
|
|
|
|
=back
|
|
|
|
=head1 COPYRIGHT
|
|
|
|
This implementation is based on the C code by M. Matsumoto
|
|
<matumoto@math.keio.ac.jp> available from
|
|
ftp://random.mat.sbg.ac.at/pub/data/tt800.c.
|
|
|
|
Translation to perl and enhancements to support multiple streams
|
|
of pseudorandom numbers by Otmar Lendl <lendl@cosy.sbg.ac.at>.
|
|
Distribution and use of this code is free.
|
|
=cut
|
|
package Math::TT800;
|
|
require Exporter;
|
|
@ISA = (Exporter);
|
|
@EXPORT = qw();
|
|
@EXPORT_OK = qw();
|
|
|
|
$VERSION = 1.0;
|
|
|
|
@default_seed = ( # default initial 25 \
|
|
seeds
|
|
0x95f24dab, 0x0b685215, 0xe76ccae7, 0xaf3ec239, 0x715fad23,
|
|
0x24a590ad, 0x69e4b5ef, 0xbf456141, 0x96bc1b7b, 0xa7bdf825,
|
|
0xc1de75b7, 0x8858a9c9, 0x2da87693, 0xb657f9dd, 0xffdc8a9f,
|
|
0x8121da71, 0x8b823ecb, 0x885d05f5, 0x4e20cd47, 0x5a9ad5d9,
|
|
0x512c0c03, 0xea857ccd, 0x4cc1d30f, 0x8891a8a1, 0xa6b7aadb );
|
|
|
|
@mag01 = ( 0x0, 0x8ebfd028 ); # this is magic vector `a', don't ch\
|
|
ange
|
|
|
|
sub new {
|
|
my $this = shift;
|
|
my $class = ref($this) || $this;
|
|
my $self = {};
|
|
bless $self, $class;
|
|
$self->initialize(@_);
|
|
return $self;
|
|
}
|
|
sub initialize {
|
|
my $self = shift;
|
|
my @state = @default_seed;
|
|
my $nr_param;
|
|
|
|
$nr_param = ($#_ < $#default_seed ) ? $#_ : $#default_seed\
|
|
;
|
|
@state[0 .. $nr_param] = @_;
|
|
$self->{"state"} = \@state;
|
|
$self->{'k'} = 0;
|
|
}
|
|
sub next_int {
|
|
my $self = shift;
|
|
my ($kk, $y);
|
|
my $state = $self->{'state'};
|
|
|
|
if ($self->{'k'} == 25) { # generate 25 wor\
|
|
ds at once
|
|
for ($kk=0; $kk < 25 - 7; $kk++) {
|
|
$state->[$kk] = $state->[$kk+7] ^
|
|
(($state->[$kk] >> 1)\
|
|
& 0x7fffffff) ^
|
|
$mag01[$state->[$kk] & 1];
|
|
}
|
|
for (; $kk<25;$kk++) {
|
|
$state->[$kk] = $state->[$kk-18] ^
|
|
(($state->[$kk] >> 1)\
|
|
& 0x7fffffff) ^
|
|
$mag01[$state->[$kk] & 1];
|
|
}
|
|
$self->{'k'} = 0;
|
|
}
|
|
$y = $state->[$self->{'k'}];
|
|
$self->{'k'}++;
|
|
|
|
$y ^= ($y << 7) & 0x2b5b2500; # s and b, magic v\
|
|
ectors
|
|
$y ^= ($y << 15) & 0xdb8b0000; # t and c, magic \
|
|
vectors
|
|
$y &= 0xffffffff; # you may delete this line if word \
|
|
size = 32
|
|
|
|
$y ^= (($y >> 16) & 0x0000ffff); # added to the 1\
|
|
994 version
|
|
}
|
|
sub next {
|
|
my $self = shift;
|
|
|
|
$self->next_int() * 2.3283064370807974e-10;
|
|
}
|