Skip to content

Commit

Permalink
added Fraction
Browse files Browse the repository at this point in the history
  • Loading branch information
uestla committed Oct 22, 2023
1 parent c40a597 commit 258f612
Show file tree
Hide file tree
Showing 4 changed files with 720 additions and 0 deletions.
228 changes: 228 additions & 0 deletions Simplex/Math/Fraction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
<?php

declare(strict_types = 1);

/**
* This file is part of the SimplexCalculator library
*
* Copyright (c) 2014 Petr Kessler (https://kesspess.cz)
*
* @license MIT
* @link https://github.com/uestla/Simplex-Calculator
*/

namespace Simplex\Math;

use Simplex\DivisionByZeroException;
use Simplex\ScientificFloatException;
use Simplex\NonNumericArgumentException;


final class Fraction implements \Stringable
{

private readonly string $n;
private readonly string $d;


public function __construct(string $n, string $d = '1')
{
if ($d === '0') {
throw new DivisionByZeroException;
}

if ($d === '-1') {
$n = mul($n, '-1');
$d = '1';

} elseif ($d !== '1') {
$gcd = gcd($n, $d);

if ($gcd !== '1') {
$n = div($n, $gcd);
$d = div($d, $gcd);
}

if (isNegative($d)) {
$n = mul($n, '-1');
$d = mul($d, '-1');
}
}

$this->n = $n;
$this->d = $d;
}


public static function create(self|string|int|float $a): self
{
if ($a instanceof self) {
return $a;
}

[$n, $d] = self::factoryParts($a);
return new self($n, $d);
}


public function getNumerator(): string
{
return $this->n;
}


public function getDenominator(): string
{
return $this->d;
}


/** a/b + c/d = (ad + bc)/bd */
public function add(self $a): self
{
return new self(
add(
mul($this->n, $a->d),
mul($this->d, $a->n),
),
mul($this->d, $a->d),
);
}


/** a/b - c/d = (ad - bc)/bd */
public function subtract(self $a): self
{
return new self(
sub(
mul($this->n, $a->d),
mul($this->d, $a->n),
),
mul($this->d, $a->d),
);
}


/** (a/b)(c/d) = (ac/bd) */
public function multiply(self|string $a): self
{
if (is_string($a)) {
return new self(
mul($this->n, $a),
$this->d,
);
}

return new self(
mul($this->n, $a->n),
mul($this->d, $a->d),
);
}


/** (a/b)/(c/d) = ad/bc */
public function divide(self $a): self
{
return new self(
mul($this->n, $a->d),
mul($this->d, $a->n),
);
}


public function abs(): self
{
return new self(
abs($this->n),
$this->d,
);
}


public function isEqualTo(self|string $a): bool
{
if (is_string($a)) {
return $this->d === '1' && $this->n === $a;
}

return $this->n === $a->n && $this->d === $a->d;
}


public function isPositive(): bool
{
return $this->n !== '0' && !$this->isNegative();
}


public function isNegative(): bool
{
return isNegative($this->n);
}


public function isLowerThan(Fraction $a): bool
{
return comp(
mul($this->n, $a->getDenominator()),
mul($a->getNumerator(), $this->d),

) === -1;
}


public function toNumericString(int $precision): string
{
return round(div($this->n, $this->d, $precision + 1), $precision);
}


public function toString(): string
{
return $this->n . ($this->d === '1' ? '' : '/' . $this->d);
}


public function __toString(): string
{
return $this->toString();
}


/** @return array{string, string} */
private static function factoryParts(string|int|float $a): array
{
if (!is_numeric($a)) {
throw new NonNumericArgumentException($a);
}

$n = (string) $a;
$d = '1';

$expPos = stripos($n, 'e'); // exponent
$dotPos = strpos($n, '.'); // decimal point

if ($expPos !== false && $dotPos !== false) {
throw new ScientificFloatException;
}

if ($expPos !== false) {
$exp = substr($n, $expPos + 1);
$n = substr($n, 0, $expPos);

if ($exp[0] === '-') { // negative exponent
$d = pow('10', substr($exp, 1));

} else {
$n = mul($n, pow('10', $exp));
}

} elseif ($dotPos !== false) {
$d = pow('10', (string) (strlen($n) - $dotPos - 1));
$n = ltrim(str_replace('.', '', $n), '0');
}

return [$n, $d];
}

}
33 changes: 33 additions & 0 deletions Simplex/exceptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,38 @@ public function __construct()
}


final class DivisionByZeroException extends SimplexException
{

public function __construct()
{
parent::__construct('Division by zero.');
}

}


final class NonNumericArgumentException extends SimplexException
{

public function __construct(string $s)
{
parent::__construct(sprintf('Non-numeric argument "%s".', $s));
}

}


final class ScientificFloatException extends SimplexException
{

public function __construct()
{
parent::__construct('Floats with scientific notation are not supported.');
}

}


abstract class SimplexException extends \Exception
{}
1 change: 1 addition & 0 deletions Simplex/simplex.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@

require_once __DIR__ . '/exceptions.php';
require_once __DIR__ . '/Math/math.php';
require_once __DIR__ . '/Math/Fraction.php';
Loading

0 comments on commit 258f612

Please sign in to comment.