Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
<?php
class SeededRandomNumberGenerator
{
/**
* An integer with the 32 least significant bits set
* 0xffffffff is a float on 32-bit platforms :-/
*/
private const MASK = \PHP_INT_SIZE === 4 ? ~0 : 0xffffffff;
/**
* @var int
*/
private $seed;
/**
* @param int $seed
*/
public function __construct(int $seed)
{
$this->seed = $seed & self::MASK;
}
/**
* Add two integers, wrap around on overflow (avoid float coersion)
* https://stackoverflow.com/questions/4068033/add-two-integers-using-only-bitwise-operators
*
* @param int $a
* @param int $b
* @return int
*/
private static function intAdd(int $a, int $b): int
{
$a &= self::MASK;
$b &= self::MASK;
$carry = $a & $b;
$result = $a ^ $b;
while ($carry) {
$shiftedCarry = $carry << 1;
$carry = $result & $shiftedCarry;
$result ^= $shiftedCarry;
}
return $result & self::MASK;
}
/**
* Multiply two integers, wrap around on overflow (avoid float coersion)
* https://stackoverflow.com/questions/4456442/multiplication-of-two-integers-using-bitwise-operators
*
* @param int $a
* @param int $b
* @return int
*/
private static function intMul(int $a, int $b): int
{
$a &= self::MASK;
$b &= self::MASK;
$result = 0;
while ($b) {
if ($b & 1) {
$result = self::intAdd($result, $a);
}
$a = ($a << 1) & self::MASK;
$b >>= 1;
}
return $result;
}
/**
* Generate a pseudo-random number between 0 and 65535 from the current seed
* https://stackoverflow.com/questions/4768180/rand-implementation
*
* @return int
*/
public function generate(): int
{
return (($this->seed = self::intAdd(self::intMul($this->seed, 214013), 2531011)) >> 16) & 0xffff;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment