NAME
Math::Random::MTwist - A fast stateful Mersenne Twister pseudo-random number generator.
SYNOPSIS
# object-oriented inteface
use Math::Random::MTwist;
my $mt = Math::Random::MTwist->new(); # seed from /dev/urandom
my $int = $mt->irand(); # [0 .. 2^64-1 or 2^32-1]
my $double = $mt->rand(73); # [0 .. 73)
$mt->goodseed(); # seed from /dev/random
$mt->savestate("/tmp/foobar"); # save current state to file
$mt->loadstate("/tmp/foobar"); # load past state from file
my @dist = map $mt->rd_triangular(1, 3, 2), 1 .. 1e3; # triangular dist.
# function-oriented interface (OO interface may be used in parallel)
use Math::Random::MTwist qw(seed32 seedfull
timeseed fastseed goodseed bestseed);
use Math::Random::MTwist qw(:seed) # gives you all of the above
use Math::Random::MTwist qw(srand rand rand32 irand irand32 irand64);
use Math::Random::MTwist qw(:rand); # gives you all of the above
use Math::Random::MTwist qw(rd_exponential rd_triangular rd_normal ...);
use Math::Random::MTwist qw(:dist); # gives you all of the above
use Math::Random::MTwist qw(savestate loadstate getstate setstate);
use Math::Random::MTwist qw(:state); # gives you all of the above
use Math::Random::MTwist qw(:all); # import all functions
DESCRIPTION
Math::Random::MTwist is a Perl interface to Geoff Kuenning's mtwist C library. It provides several seeding methods and various random number distributions.
All functions are available through a function-oriented interface and an object-oriented interface. The function-oriented interface maintains a single global state while the OO interface gives you an individual state per instance.
The function-oriented interface provides drop-in replacements for Perl's built-in rand()
and srand()
functions.
If you use
the module with an import list, the global state is seeded automatically using fastseed()
. In this case, if you need the MT_
constants, you must import them explicitly through the :DEFAULT
tag.
FLOATING POINT PRECISION
The rand() and rd_l* functions return whatever NV type your Perl uses (e.g. double, long double or __float128 [quadmath]). However, before version 0.22, the results were limited to 64-bit precision. Since version 0.22 you get the full precision of your Perl's NV.
If your Perl uses long doubles or quadmath, the distribution functions use the corresponding math functions (sqrtl/sqrtq etc.).
The rand32() and non-l rd_* functions always return a double and provide 32-bit precision.
CONSTRUCTOR
- new(), new($seed)
-
Takes an optional argument specifying the seed. If you omit the seed,
MT_FASTSEED
is the default.The seed can be a number (will be coerced to an unsigned 32-bit integer), an array reference holding up to 624 such numbers (missing values are padded with zeros, excess values are ignored) or one of the special values
MT_TIMESEED
,MT_FASTSEED
,MT_GOODSEED
orMT_BESTSEED
that choose one of the corresponding seeding methods (see below).Each instance maintains an individual PRNG state allowing multiple independent random number streams.
SEEDING
- seed32($number)
-
Seeds the generator with
$number
, coercing it to an unsigned 32-bit integer. Calls mtwist'smts_seed32new()
. Returns the seed. - srand(), srand($number)
-
Calls
seed32
if$number
is given,fastseed()
otherwise. Returns the seed. - seedfull($seeds)
-
Seeds the generator with up to 624 numbers from the array reference
$seeds
. The values are coerced to unsigned 32-bit integers. Missing or undefined values are taken as zero, excess values are ignored. Croaks unless you supply at least one non-zero value. Calls mtwist'smts_seedfull()
. Returns nothing. - fastseed()
-
Seeds the generator with 4 bytes read from
/dev/urandom
(preferably via getrandom()) if available, otherwise from the system time (see details undertimeseed()
). Calls mtwist'smts_seed()
. Returns the seed.This method is called by
new(MT_FASTSEED)
. - goodseed()
-
Seeds the generator with 4 bytes read from
/dev/random
(preferably via getrandom()) if available, otherwise from the system time (see details undertimeseed()
). Calls mtwist'smts_goodseed()
. Returns the seed.This method is called by
new(MT_GOODSEED)
. - bestseed()
-
Seeds the generator with 642 integers read from
/dev/random
if available. This might take a very long time and is probably not worth the waiting. If/dev/random
is unavailable or there was a reading error it falls back togoodseed()
. Calls mtwist'smts_bestseed()
.This method is called by
new(MT_BESTSEED)
. - timeseed()
-
Seeds the generator from the current system time obtained from
clock_gettime()
(if your system supports CLOCK_MONOTONIC) orTime::HiRes::gettimeofday()
by calculating the total nanoseconds (or microseconds), XORing them with a memory address (hoping for some more randomness from ASLR) and coercing the result to an unsigned 32-bit integer.Returns the seed.
This method is called by
new(MT_TIMESEED)
.timeseed
doesn't correspond to any of mtwist's functions. The rationale behind it is that mtwist uses the system time if neither/dev/urandom
nor/dev/random
is available. On Windows, the time source it uses has only millisecond resolution, so I tried to pimp it a bit.
STATE HANDLING
- savestate($filename or $filehandle)
-
Saves the current state of the generator to a file given either by a filename (file will be truncated) or an open Perl file handle.
Returns 1 on success, 0 on error (you might want to check
$!
). - loadstate($filename or $filehandle)
-
Loads the state of the generator from a file given either by a filename or an open Perl file handle.
Returns 1 on success, 0 on error (you might want to check
$!
). - getstate()
-
Returns the current state of the generator as a binary string.
- setstate($string)
-
Sets the state of the generator from
$string
, which you should have obtained withgetstate()
. croak()s if$string
is not a string of the correct size.
savestate()
and loadstate()
are portable because they save the state as decimal numbers. getstate()
and setstate()
are not portable because they simply use a memory dump for laziness reasons.
However, depending on your system's architecture, you can convert getstate()
to savestate()
format using something like join ' ', (reverse unpack 'L624i', getstate())[1..624,0];
.
UNIFORMLY DISTRIBUTED RANDOM NUMBERS
- irand()
-
Returns a random unsigned integer, 64-bit if your system supports it (see
irand64()
), 32-bit otherwise. - irand32()
-
Returns a random unsigned 32-bit integer. Calls mtwist's
mts_lrand()
. - irand64()
-
If your Perl uses 64-bit integers, returns a 64-bit unsigned integer. If your Perl uses 32-bit integers but your OS knows the
uint64_t
type, returns a 64-bit unsigned integer as a decimal string. Otherwise it returns undef. Calls mtwist'smts_llrand()
. - irand128()
-
That's pretty standard. ;-) No, it just works with a GCC that has __int128. Returns undef otherwise.
- rand(), rand($bound)
-
Returns a random double with 53-bit precision in the range
[0, $bound)
. Calls mtwist'smts_ldrand()
.$bound
may be negative. If$bound
is omitted or zero it defaults to 1. - rand32(), rand32($bound)
-
Returns a random double with 32-bit precision in the range
[0, $bound)
. Slightly faster than rand(). Calls mtwist'smts_drand()
.$bound
may be negative. If$bound
is omitted or zero it defaults to 1. - rd_iuniform(IV lower, IV upper)
-
Returns a signed integer in the range [lower, upper) of your Perl's IVTYPE (32-bit or 64-bit). Takes signed integer arguments.
- rd_iuniform32(IV lower, IV upper)
-
Returns a signed 32-bit integer in the range [lower, upper). Takes signed 32-bit arguments.
- rd_iuniform64(IV lower, IV upper)
-
Returns a signed 64-bit integer in the range [lower, upper) if your Perl uses 64-bit integers. Otherwise it returns undef. Note that unlike irand64() it doesn't return a decimal string in the 32-bit IV + uint64_t case because you could only pass it 32-bit arguments anyway.
- rd_(l)uniform(NV lower, NV upper)
-
Generates floating point numbers from a uniform distribution in the range [lower, upper).
- randstr(), randstr($length)
-
Returns a random binary string. The default length is 8 bytes. Returns undef if there is not enough memory.
NON-UNIFORMLY DISTRIBUTED RANDOM NUMBERS
With the exception of rd_double()
the following methods come in two variants: rd_xxx
and rd_lxxx
. They all return a double but the rd_xxx
versions provide 32-bit precision while the rd_lxxx
versions provide 53-bit precision at the expense of speed.
TODO: If your Perl's NVs are long doubles, the rd_lxxx
functions provide 64-bit precision.
- rd_double(), rd_double($index)
-
This is kind of a FUNction (that's the "Fun with flags" sort of fun).
It generates a random double in the complete (signed) double range. It does that by drawing a random 64-bit integer (if available, otherwise two 32-bit integers) and interpreting the bit pattern as a double. That's the same as saying
unpack 'd', pack 'Q', irand64()
. The results follow a Benford distribution (each range [2^n, 2^(n+1)[ can hold 2^52 values). Be prepared to meet some NaNs, Infs and subnormals (see POSIX::2008 for floating point check functions).In scalar context it returns a double. In list context it returns the double, the corresponding integer (undef if your Perl doesn't have 64-bit integers) and the packed string representation.
For convenience, you can call rd_double() with an optional argument $index to get the same result as with (rd_double())[$index], just a bit more efficiently.
- rd_(l)exponential(NV mean)
-
Generates an exponential distribution with the given mean.
- rd_(l)erlang(IV k, NV mean)
-
Generates an Erlang-k distribution with the given mean.
- rd_(l)weibull(NV shape, NV scale)
-
Generates a Weibull distribution with the given shape and scale.
- rd_(l)normal(NV mean, NV sigma)
-
Generates a normal (Gaussian) distribution with the given mean and standard deviation sigma.
- rd_(l)lognormal(NV shape, NV scale)
-
Generates a log-normal distribution with the given shape and scale.
- rd_(l)triangular(NV lower, NV upper, NV mode)
-
Generates a triangular distribution in the range
[lower, upper)
with the given mode.
EXPORTS
By default the module exports the constants MT_TIMESEED, MT_FASTSEED, MT_GOODSEED and MT_BESTSEED that can be used as an argument to the constructor.
The following export tags are available:
- :dist
-
rd_double rd_erlang rd_lerlang rd_exponential rd_lexponential rd_lognormal rd_llognormal rd_normal rd_lnormal rd_triangular rd_ltriangular rd_weibull rd_lweibull
- :rand
-
rand rand rand32 rand64 irand irand32 irand64
- :seed
-
seed32 seedfull timeseed fastseed goodseed bestseed
- :state
-
savestate loadstate getstate setstate
- :all
-
All of the above.
- :DEFAULT
-
MT_TIMESEED MT_FASTSEED MT_GOODSEED MT_BESTSEED
NOTES
This module is not fork()/clone()
aware, i.e. you have to take care of re-seeding/re-instantiating in new processes/threads yourself (POSIX::AtFork might be useful here).
Imported functions and OO methods have the same names. This works by symbol table "redirection", e.g. non-OO irand() is actually _irand() internally and so on (note the underscore). The minor drawback is that you can't use fully qualified names like Math::Random::MTwist::irand()
etc. Instead you have to say Math::Random::MTwist::_irand()
. I considered avoiding this by checking if the first argument is a blessed reference but I discarded that in favor of speed.
I made some changes to the mtwist library (not affecting the algorithms) to adapt it to the Perl module. These changes are documented in the patches/ directory.
SEE ALSO
https://www.cs.hmc.edu/~geoff/mtwist.html
Math::Random::MT and Math::Random::MT::Auto are significantly slower than Math::Random::MTwist. MT::Auto has some additional sophisticated features but it depends on non-core modules.
AUTHOR
Carsten Gaebler (cgpan ʇɐ gmx ʇop de).
COPYRIGHT
Perl and XS portion: Copyright © 2014 by Carsten Gaebler.
mtwist C library: Copyright © 2001, 2002, 2010, 2012, 2013 by Geoff Kuenning.
LICENSE
Perl and XS portion: WTFPL.
mtwist C library: LGPL