package Math::Random::MT;

use strict;
use Carp;
use DynaLoader;
use vars qw( @ISA $VERSION );

my $gen = undef;
@ISA = qw( DynaLoader );
$VERSION = '1.17';

bootstrap Math::Random::MT $VERSION;

sub new
{
    my ($class, @seeds) = @_;

    my $self = Math::Random::MT::init();
    $self->set_seed(@seeds);

    return $self;
}

sub set_seed
{
    my ($self, @seeds) = @_;
    @seeds > 1 ? $self->setup_array(@seeds) :
                 $self->init_seed(defined $seeds[0] ? $seeds[0] : _rand_seed());
    return $self->get_seed;
}

sub srand
{
    my (@seeds) = @_;
    $gen = Math::Random::MT->new(@seeds);
    return $gen->get_seed;
}

sub rand
{
    my ($self, $N) = @_;

    unless (ref $self) {
        $N = $self;
        Math::Random::MT::srand() unless defined $gen;
        $self = $gen;
    }

    return ($N || 1) * $self->genrand();
}

sub irand
{
    my ($self) = @_;

    unless (ref $self) {
        Math::Random::MT::srand() unless defined $gen;
        $self = $gen;
    }

    return $self->genirand();
}


# Generate a random seed using the built-in PRNG.

sub _rand_seed {
    my ($self) = @_;

    # Get a seed at random through Perl's CORE::rand(). We do not call
    # CORE::srand() to avoid altering the random numbers that other parts of
    # the running script might be using. The seeds obtained by rapid calls to
    # the _rand_seed() function are all different.
    
    return int(CORE::rand(2**32));
}

sub import
{
    no strict 'refs';
    my $pkg = caller;
    foreach my $sym (@_) {
        if ($sym eq 'srand' || $sym eq 'rand' || $sym eq 'irand') {
            *{"${pkg}::$sym"} = \&$sym;
        }
    }
}

1;

__END__

=head1 NAME

Math::Random::MT - The Mersenne Twister PRNG

=head1 SYNOPSIS

  ## Object-oriented interface:
  use Math::Random::MT;
  $gen = Math::Random::MT->new()        # or...
  $gen = Math::Random::MT->new($seed);  # or...
  $gen = Math::Random::MT->new(@seeds);
  $seed = $gen->get_seed();             # seed used to generate the random numbers
  $rand = $gen->rand(42);               # random number in the interval [0, 42)
  $dice = int($gen->rand(6)+1);         # random integer between 1 and 6
  $coin = $gen->rand() < 0.5 ?          # flip a coin
    "heads" : "tails"
  $int = $gen->irand();                 # random integer in [0, 2^32-1]

  ## Function-oriented interface:
  use Math::Random::MT qw(srand rand irand);
  # now use srand() and rand() as you usually do in Perl

=head1 DESCRIPTION

The Mersenne Twister is a pseudorandom number generator developed by
Makoto Matsumoto and Takuji Nishimura. It is described in their paper at
<URL:http://www.math.keio.ac.jp/~nisimura/random/doc/mt.ps>. This algorithm
has a very uniform distribution and is good for modelling purposes but do not
use it for cryptography.

This module implements two interfaces:

=head2 Object-oriented interface

=over

=item new()

Creates a new generator that is automatically seeded based on gettimeofday.

=item new($seed)

Creates a new generator seeded with an unsigned 32-bit integer.

=item new(@seeds)

Creates a new generator seeded with an array of (up to 624) unsigned
32-bit integers.

=item set_seed()

Seeds the generator and returns the seed used. It takes the same arguments as
I<new()>.

=item get_seed()

Retrieves the value of the seed used.

=item rand($num)

Behaves exactly like Perl's builtin rand(), returning a number uniformly
distributed in [0, $num) ($num defaults to 1).

=item irand()

Returns a 32-bit integer, i.e. an integer uniformly distributed in [0, 2^32-1].

=back

=head2 Function-oriented interface

=over

=item srand($seed)

Behaves just like Perl's builtin srand(). As in Perl >= 5.14, the seed is
returned. If you use this interface, it is strongly recommended that you
call I<srand()> explicitly, rather than relying on I<rand()> to call it the
first time it is used.

=item rand($num)

Behaves exactly like Perl's builtin rand(), returning a number uniformly
distributed in [0, $num) ($num defaults to 1).

=item irand()

Returns a 32-bit integer, i.e. an integer uniformly distributed in [0, 2^32-1].

=back

=head1 SEE ALSO

<URL:http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html>

Data::Entropy

=head1 ACKNOWLEDGEMENTS

=over 4

=item Sean M. Burke

For giving me the idea to write this module.

=item Philip Newton

For several useful patches.

=item Florent Angly

For implementing seed generation and retrieval.

=back

=head1 AUTHOR

Abhijit Menon-Sen <ams@toroid.org>

Copyright 2001 Abhijit Menon-Sen. All rights reserved.

Based on the C implementation of MT19937
Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura

This software is distributed under a (three-clause) BSD-style license.
See the LICENSE file in the distribution for details.
