Skip to content

Instantly share code, notes, and snippets.

@natmchugh
Created February 18, 2016 14:14
Show Gist options
  • Save natmchugh/df08d68fdfcc14382577 to your computer and use it in GitHub Desktop.
Save natmchugh/df08d68fdfcc14382577 to your computer and use it in GitHub Desktop.
Pure PHP implementation of mt19937 with standard or PHP behaviours
<?php
class MersenneTwister
{
const STANDARD = 1;
const PHP = 2;
// Create a length 624 array to store the state of the generator
private $MT;
private $index;
public function __construct($seed, $mode = self::STANDARD)
{
$this->initialize_generator($seed);
$this->mode = $mode;
}
public function setInternalState($state, $index)
{
$this->MT = $state;
$this->index = $index;
}
// Initialize the generator from a seed
function initialize_generator($seed) {
$this->MT = new \SplFixedArray(624);
$this->index = 0;
$this->MT[0] = $seed;
for ($i = 1; $i < 624; $i++) { // loop over each other element
$this->MT[$i] = (0x6c078965 * ($this->MT[$i-1] ^ ($this->MT[$i-1] >> 30)) + $i) & 0xffffffff;// 0x6c078965
}
}
// Extract a tempered pseudorandom number based on the index-th value,
// calling generate_numbers() every 624 numbers
function extract_number() {
if ($this->index == 0) {
$this->generate_numbers();
}
$y = $this->MT[$this->index];
$y = $y ^ ($y >> 11);
$y = $y ^ (($y << 7) & 0x9d2c5680); // 0x9d2c5680
$y = $y ^ (($y << 15) & 0xefc60000); // 0xefc60000
$y = $y ^ ($y >> 18);
$this->index = ($this->index + 1) % 624;
return $y >> 1;
}
// Generate an array of 624 untempered numbers
function generate_numbers() {
foreach ($this->MT as $i => $mt) {
$z = $mt;
$y = ($mt & 0x80000000) + ($this->MT[($i+1) % 624] & 0x7fffffff); // bits 0-30 (first 31 bits) of MT[...]
$this->MT[$i] = $this->MT[(($i + 397) % 624)] ^ ($y >> 1);
$compare = $this->mode == self::PHP ? $z: $y;
if (($compare % 2) != 0) { // z is odd
$this->MT[$i] ^= 0x9908b0df;
}
}
}
}
$mt = new MersenneTwister(12345678, MersenneTwister::STANDARD);
for ($i=0; $i<16; $i++) {
echo $mt->extract_number(),PHP_EOL;
}
echo PHP_EOL;
$x = 0;
for ($i=0; $i<1024; $i++) {
$x ^= $mt->extract_number();
}
echo $x.PHP_EOL;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment