Skip to content

Instantly share code, notes, and snippets.

@ostrolucky
Last active May 14, 2025 11:21
Show Gist options
  • Save ostrolucky/f49d0dc3a564ca8b46be784786061175 to your computer and use it in GitHub Desktop.
Save ostrolucky/f49d0dc3a564ca8b46be784786061175 to your computer and use it in GitHub Desktop.
Linear congruantial generator in PHP
<?php
namespace App\Tests\Unit\SharedKernel\Utils;
use App\SharedKernel\Utils\LinearCongruentialGenerator;
use PHPUnit\Framework\TestCase;
class LinearCongruantialGeneratorTest extends TestCase
{
/**
* @testWith ["0", "5", ["1", "0", "5", "4", "3"]]
* ["1", "3", ["3", "2", "1", "3"]]
* ["0", "340282366920938463463374607431768211456", ["50", "65", "80", "95"]]
*/
public function testGenerate(string $min, string $max, array $expected): void
{
$generator = new LinearCongruentialGenerator($min, $max, $min);
$this->assertSame($expected, array_map(fn() => $generator->generate(), $expected));
$this->assertNotSame($expected, array_map(fn() => $generator->generate(), $expected));
}
}
<?php
namespace App\SharedKernel\Utils;
/** @see https://github.com/symbiotic-php/linear-congruential-generator */
class LinearCongruentialGenerator
{
/**
* @param numeric-string $min
* @param numeric-string $max
* @param \GMP|numeric-string $seed
*/
public function __construct(
private string $min,
private string $max,
public \GMP|string $seed,
) {
}
/** @return numeric-string */
public function generate(): string
{
$range = \gmp_sub($this->max, $this->min);
$primeNumber = \gmp_nextprime($range);
$secondPrimeNumber = \gmp_nextprime(\gmp_mul($range, '2'));
$result = \gmp_mod(
\gmp_add(\gmp_mul($secondPrimeNumber, $this->seed), $primeNumber),
\gmp_add($range, '1'),
);
$this->seed = \gmp_add($this->seed, '1');
/** @phpstan-ignore return.type */
return \gmp_strval(\gmp_add($result, $this->min));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment