razionale.php
<?php
declare(strict_types=1);
class razionale
{
private int $num;
private int $den;
public function __construct(int $num = 0, int $den = 1)
{
$this->num = $num;
$this->den = $den;
}
public function sign(): int
{
return $this->num <=> 0;
}
public function addfrac(razionale $x, razionale $y): void
{
$somma = new razionale();
if ($x->num == 0) {
$this->num = $y->num;
$this->den = $y->den;
} else if ($y->num() == 0) {
$this->num = $x->num;
$this->den = $x->den;
} else {
$somma->num = $x->num * $y->den + $x->den * $y->num;
$somma->den = $x->den * $y->den;
$somma->normalize();
$this->num = $somma->num;
$this->den = $somma->den;
}
}
public function num(): int
{
return $this->num;
}
public function normalize(): self
{
$s = $this->sign_int($this->den);
if ($s == 0) printf("Zero denominator.");
else if ($s < 0) {
$this->den = -$this->den;
$this->num = -$this->num;
}
$g = $this->gcd($this->num, $this->den);
if ($g != 1) {
$this->num /= $g;
$this->den /= $g;
}
return $this;
}
public function sign_int(int $i): int
{
return $i <=> 0;
}
public function gcd(int $x, int $y): int
{
$a = abs($x);
$b = abs($y);
if ($b > $a) {
$tmp = $a;
$a = $b;
$b = $tmp;
}
for (; ;) {
if ($b == 0) return $a;
else if ($b == 1) return $b;
else {
$tmp = $b;
$b = $a % $b;
$a = $tmp;
}
}
}
public function mulfrac(razionale $x, razionale $y): void
{
$prodotto = new razionale();
if ($x->num == 0 || $y->num == 0) {
$this->num = 0;
$this->den = 1;
} else if ($x->value() == 1) {
$this->num = $y->num;
$this->den = $y->den;
} else if ($y->value() == 1) {
$this->num = $x->num;
$this->den = $x->den;
} else if ($x->value() == -1) {
$this->num = -$y->num;
$this->den = $y->den;
} else if ($y->value() == -1) {
$this->num = -$x->num;
$this->den = $x->den;
} else {
$prodotto->num = $x->num * $y->num;
$prodotto->den = $x->den * $y->den;
$prodotto->normalize();
$this->num = $prodotto->num;
$this->den = $prodotto->den;
}
}
public function value(): float
{
return $this->den != 0 ? $this->num / $this->den : NAN;
}
public function divfrac(razionale $x, razionale $y): void
{
$quoziente = new razionale();
if ($x->num == 0) {
$this->num = 0;
$this->den = 1;
} else if ($y->num == 0) {
printf("Division by zero");
} else {
// echo "\n<br />divido " . $x->fractoa() . " per " . $y->fractoa();
$quoziente->num = $x->num * $y->den;
$quoziente->den = $x->den * $y->num;
$quoziente->normalize();
$this->num = $quoziente->num;
$this->den = $quoziente->den;
// echo " e ottengo " . $this->fractoa() . "<br />\n";
}
}
public function negatefrac(): void
{
$this->num = -$this->num;
}
public function invertfrac(): void
{
$tmp = $this->num;
$this->num = $this->den;
$this->den = $tmp;
$s = $this->sign_int($this->den);
if ($s == 0) exit(1);
else if ($s < 0) {
$this->den = -$this->den;
$this->num = -$this->num;
}
}
public function comparefrac(razionale $x, razionale $y): int
{
$this->subfrac($x, $y);
return $this->sign_int($this->num);
}
public function subfrac(razionale $x, razionale $y): void
{
$differenza = new razionale();
if ($x->num == 0) {
$this->num = -$y->num;
$this->den = $y->den;
} else if ($y->num == 0) {
$this->num = $x->num;
$this->den = $x->den;
} else {
$differenza->num = $x->num * $y->den - $x->den * $y->num;
$differenza->den = $x->den * $y->den;
$differenza->normalize();
$this->num = $differenza->num;
$this->den = $differenza->den;
}
}
public function scanfrac(string $x): void
{
// Se c'e' uno slash e' espresso direttamente come frazione
if (empty(trim($x))) {
$this->num = 0;
$this->den = 1;
} else if (strchr($x, '/')) {
$num_den = explode('/', $x, strlen($x));
$this->num = (int)trim($num_den[0]);
$this->den = (int)trim($num_den[1]);
} else if (strchr($x, '.')) { // e' espresso come decimale
// facciamo fare il lavoro al PHP
$float = (float)$x;
// quante cifre dopo la virgola?
$decimali = strlen(strchr($x, '.')) - 1;
$this->den = (int)pow(10, $decimali);
$this->num = (int)round($float * $this->den);
} else { // e' un intero
$this->num = (int)$x;
$this->den = 1;
}
}
public function fractoa(): string
{
if ($this->den == 1)
$str = sprintf("%d", $this->num);
else
$str = sprintf("%d/%d", $this->num, $this->den);
return $str;
}
public function den(): int
{
return $this->den;
}
public function set(int $num, int $den): void
{
$this->num = $num;
$this->den = $den;
}
}