The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

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 or MT_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's mts_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's mts_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 under timeseed()). Calls mtwist's mts_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 under timeseed()). Calls mtwist's mts_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 to goodseed(). Calls mtwist's mts_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) or Time::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 with getstate(). 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's mts_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's mts_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's mts_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