PyInt.php
PHP
Path: src/Util/Math/Int/PyInt.php
<?php
namespace mini\Util\Math\Int;
/**
* Reference implementation using Python interpreter
*
* Delegates all arithmetic to Python's arbitrary precision integers.
* Useful for testing correctness of other implementations.
* NOT for production use - spawns a process per operation.
*/
final class PyInt implements IntValue
{
private function __construct(
private readonly string $value
) {}
public static function of(string|int $value): static
{
return new self(self::py("print(int('{$value}'))"));
}
public static function zero(): static
{
return new self('0');
}
public static function one(): static
{
return new self('1');
}
// ─────────────────────────────────────────────────────────────────────────
// Arithmetic
// ─────────────────────────────────────────────────────────────────────────
public function add(string|int|IntValue $other): static
{
$b = $this->toStr($other);
return new self(self::py("print({$this->value} + int('{$b}'))"));
}
public function subtract(string|int|IntValue $other): static
{
$b = $this->toStr($other);
return new self(self::py("print({$this->value} - int('{$b}'))"));
}
public function multiply(string|int|IntValue $other): static
{
$b = $this->toStr($other);
return new self(self::py("print({$this->value} * int('{$b}'))"));
}
public function divide(string|int|IntValue $other): static
{
$b = self::py("print(int('{$this->toStr($other)}'))");
if ($b === '0') {
throw new \DivisionByZeroError('Division by zero');
}
// Python's // truncates toward negative infinity, but PHP truncates toward zero
// Use: sign * (abs(a) // abs(b)) for PHP-compatible truncation
$code = "a={$this->value}; b=int('{$b}'); s=(-1 if (a<0)!=(b<0) else 1); print(s*(abs(a)//abs(b)))";
return new self(self::py($code));
}
public function modulus(string|int|IntValue $other): static
{
$b = self::py("print(int('{$this->toStr($other)}'))");
if ($b === '0') {
throw new \DivisionByZeroError('Modulus by zero');
}
// Python's % follows divisor sign, PHP's follows dividend sign
// Use: a - truncdiv(a,b)*b where truncdiv truncates toward zero
$code = "a={$this->value}; b=int('{$b}'); s=(-1 if (a<0)!=(b<0) else 1); q=s*(abs(a)//abs(b)); print(a - q*b)";
return new self(self::py($code));
}
public function power(int $exponent): static
{
if ($exponent < 0) {
throw new \InvalidArgumentException('Negative exponents not supported for integers');
}
return new self(self::py("print({$this->value} ** {$exponent})"));
}
public function negate(): static
{
if ($this->value === '0') {
return $this;
}
return new self(self::py("print(-({$this->value}))"));
}
public function absolute(): static
{
return new self(self::py("print(abs({$this->value}))"));
}
// ─────────────────────────────────────────────────────────────────────────
// Comparison
// ─────────────────────────────────────────────────────────────────────────
public function compare(string|int|IntValue $other): int
{
$b = $this->toStr($other);
$result = self::py("a={$this->value}; b=int('{$b}'); print(-1 if a<b else (1 if a>b else 0))");
return (int) $result;
}
public function equals(string|int|IntValue $other): bool
{
return $this->compare($other) === 0;
}
public function lessThan(string|int|IntValue $other): bool
{
return $this->compare($other) < 0;
}
public function greaterThan(string|int|IntValue $other): bool
{
return $this->compare($other) > 0;
}
public function lessThanOrEqual(string|int|IntValue $other): bool
{
return $this->compare($other) <= 0;
}
public function greaterThanOrEqual(string|int|IntValue $other): bool
{
return $this->compare($other) >= 0;
}
// ─────────────────────────────────────────────────────────────────────────
// Predicates
// ─────────────────────────────────────────────────────────────────────────
public function isZero(): bool
{
return $this->value === '0';
}
public function isPositive(): bool
{
return $this->value !== '0' && !str_starts_with($this->value, '-');
}
public function isNegative(): bool
{
return str_starts_with($this->value, '-');
}
// ─────────────────────────────────────────────────────────────────────────
// Conversion
// ─────────────────────────────────────────────────────────────────────────
public function toInt(): int
{
$max = (string) PHP_INT_MAX;
$min = (string) PHP_INT_MIN;
// Compare magnitudes to check overflow
if ($this->isNegative()) {
if ($this->compare($min) < 0) {
throw new \OverflowException('Value exceeds native int range');
}
} else {
if ($this->compare($max) > 0) {
throw new \OverflowException('Value exceeds native int range');
}
}
return (int) $this->value;
}
public function __toString(): string
{
return $this->value;
}
// ─────────────────────────────────────────────────────────────────────────
// Internal helpers
// ─────────────────────────────────────────────────────────────────────────
private function toStr(string|int|IntValue $value): string
{
return (string) $value;
}
private static function py(string $code): string
{
$result = shell_exec("python3 -c " . escapeshellarg($code) . " 2>&1");
if ($result === null) {
throw new \RuntimeException('Failed to execute Python');
}
return trim($result);
}
}