mirror of
https://github.com/danog/math.git
synced 2024-11-30 04:19:31 +01:00
Introducing a specific DivisionByZeroException
This commit is contained in:
parent
7680dcf634
commit
ed8e1075e2
@ -3,6 +3,7 @@
|
||||
namespace Brick\Math;
|
||||
|
||||
use Brick\Math\Exception\ArithmeticException;
|
||||
use Brick\Math\Exception\DivisionByZeroException;
|
||||
use Brick\Math\Internal\Calculator;
|
||||
|
||||
/**
|
||||
@ -221,6 +222,7 @@ final class BigDecimal extends BigNumber implements \Serializable
|
||||
*
|
||||
* @return BigDecimal
|
||||
*
|
||||
* @throws DivisionByZeroException If the divisor is zero.
|
||||
* @throws ArithmeticException If RoundingMode::UNNECESSARY is provided and rounding was necessary.
|
||||
* @throws \InvalidArgumentException If any of the arguments is not valid.
|
||||
*/
|
||||
@ -229,7 +231,7 @@ final class BigDecimal extends BigNumber implements \Serializable
|
||||
$that = BigDecimal::of($that);
|
||||
|
||||
if ($that->isZero()) {
|
||||
throw ArithmeticException::divisionByZero();
|
||||
throw DivisionByZeroException::divisionByZero();
|
||||
}
|
||||
|
||||
if ($scale === null) {
|
||||
@ -355,14 +357,14 @@ final class BigDecimal extends BigNumber implements \Serializable
|
||||
*
|
||||
* @return BigDecimal[] An array containing the quotient and the remainder.
|
||||
*
|
||||
* @throws ArithmeticException If the divisor is zero.
|
||||
* @throws DivisionByZeroException If the divisor is zero.
|
||||
*/
|
||||
public function divideAndRemainder($that)
|
||||
{
|
||||
$that = BigDecimal::of($that);
|
||||
|
||||
if ($that->isZero()) {
|
||||
throw ArithmeticException::divisionByZero();
|
||||
throw DivisionByZeroException::divisionByZero();
|
||||
}
|
||||
|
||||
$p = $this->valueWithMinScale($that->scale);
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace Brick\Math;
|
||||
|
||||
use Brick\Math\Exception\ArithmeticException;
|
||||
use Brick\Math\Exception\DivisionByZeroException;
|
||||
use Brick\Math\Internal\Calculator;
|
||||
|
||||
/**
|
||||
@ -255,7 +256,7 @@ final class BigInteger extends BigNumber implements \Serializable
|
||||
*
|
||||
* @return BigInteger
|
||||
*
|
||||
* @throws ArithmeticException If the divisor is zero.
|
||||
* @throws DivisionByZeroException If the divisor is zero.
|
||||
*/
|
||||
public function dividedBy($that)
|
||||
{
|
||||
@ -266,7 +267,7 @@ final class BigInteger extends BigNumber implements \Serializable
|
||||
}
|
||||
|
||||
if ($that->value === '0') {
|
||||
throw ArithmeticException::divisionByZero();
|
||||
throw DivisionByZeroException::divisionByZero();
|
||||
}
|
||||
|
||||
list ($quotient) = Calculator::get()->div($this->value, $that->value);
|
||||
@ -281,14 +282,14 @@ final class BigInteger extends BigNumber implements \Serializable
|
||||
*
|
||||
* @return BigInteger[] An array containing the quotient and the remainder.
|
||||
*
|
||||
* @throws ArithmeticException If the divisor is zero.
|
||||
* @throws DivisionByZeroException If the divisor is zero.
|
||||
*/
|
||||
public function divideAndRemainder($that)
|
||||
{
|
||||
$that = BigInteger::of($that);
|
||||
|
||||
if ($that->value === '0') {
|
||||
throw ArithmeticException::divisionByZero();
|
||||
throw DivisionByZeroException::divisionByZero();
|
||||
}
|
||||
|
||||
list ($quotient, $remainder) = Calculator::get()->div($this->value, $that->value);
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace Brick\Math;
|
||||
|
||||
use Brick\Math\Exception\ArithmeticException;
|
||||
use Brick\Math\Exception\DivisionByZeroException;
|
||||
|
||||
/**
|
||||
* Common interface for arbitrary-precision numbers.
|
||||
@ -42,11 +43,12 @@ abstract class BigNumber
|
||||
* @return static
|
||||
*
|
||||
* @throws \InvalidArgumentException If the number is not valid.
|
||||
* @throws DivisionByZeroException If the value represents a rational number with a denominator of zero.
|
||||
*/
|
||||
public static function of($value)
|
||||
{
|
||||
try {
|
||||
if ($value instanceof BigNumber) {
|
||||
if ($value instanceof BigNumber) {
|
||||
try {
|
||||
switch (static::class) {
|
||||
case BigInteger::class:
|
||||
return $value->toBigInteger();
|
||||
@ -60,33 +62,43 @@ abstract class BigNumber
|
||||
default:
|
||||
return $value;
|
||||
}
|
||||
} catch (ArithmeticException $e) {
|
||||
$className = substr(static::class, strrpos(static::class, '\\') + 1);
|
||||
|
||||
throw new \InvalidArgumentException('Cannot convert value to a ' . $className . ' without losing precision.');
|
||||
}
|
||||
}
|
||||
|
||||
if (is_int($value)) {
|
||||
switch (static::class) {
|
||||
case BigDecimal::class:
|
||||
return new BigDecimal((string) $value);
|
||||
|
||||
case BigRational::class:
|
||||
return new BigRational(new BigInteger((string) $value), new BigInteger('1'));
|
||||
|
||||
default:
|
||||
return new BigInteger((string) $value);
|
||||
}
|
||||
}
|
||||
|
||||
$value = (string) $value;
|
||||
|
||||
if (preg_match(BigNumber::REGEXP, $value, $matches) !== 1) {
|
||||
throw new \InvalidArgumentException('The given value does not represent a valid number.');
|
||||
}
|
||||
|
||||
if (isset($matches['denominator'])) {
|
||||
$numerator = BigNumber::cleanUp($matches['integral']);
|
||||
$denominator = ltrim($matches['denominator'], '0');
|
||||
|
||||
if ($denominator === '') {
|
||||
throw DivisionByZeroException::denominatorMustNotBeZero();
|
||||
}
|
||||
|
||||
if (is_int($value)) {
|
||||
switch (static::class) {
|
||||
case BigDecimal::class:
|
||||
return new BigDecimal((string) $value);
|
||||
|
||||
case BigRational::class:
|
||||
return new BigRational(new BigInteger((string) $value), new BigInteger('1'));
|
||||
|
||||
default:
|
||||
return new BigInteger((string) $value);
|
||||
}
|
||||
}
|
||||
|
||||
$value = (string) $value;
|
||||
|
||||
if (preg_match(BigNumber::REGEXP, $value, $matches) !== 1) {
|
||||
throw new \InvalidArgumentException('The given value does not represent a valid number.');
|
||||
}
|
||||
|
||||
if (isset($matches['denominator'])) {
|
||||
$numerator = BigNumber::cleanUp($matches['integral']);
|
||||
$denominator = BigNumber::cleanUp($matches['denominator']); // @todo doesn't need sign check
|
||||
|
||||
$result = new BigRational(new BigInteger($numerator), new BigInteger($denominator), true);
|
||||
$result = new BigRational(new BigInteger($numerator), new BigInteger($denominator), false);
|
||||
|
||||
try {
|
||||
switch (static::class) {
|
||||
case BigInteger::class:
|
||||
return $result->toBigInteger();
|
||||
@ -97,23 +109,29 @@ abstract class BigNumber
|
||||
default:
|
||||
return $result;
|
||||
}
|
||||
} elseif (isset($matches['fractional']) || isset($matches['exponent'])) {
|
||||
$fractional = isset($matches['fractional']) ? $matches['fractional'] : '';
|
||||
$exponent = isset($matches['exponent']) ? (int) $matches['exponent'] : 0;
|
||||
} catch (ArithmeticException $e) {
|
||||
$className = substr(static::class, strrpos(static::class, '\\') + 1);
|
||||
|
||||
$unscaledValue = BigNumber::cleanUp($matches['integral'] . $fractional);
|
||||
throw new \InvalidArgumentException('Cannot convert value to a ' . $className . ' without losing precision.');
|
||||
}
|
||||
} elseif (isset($matches['fractional']) || isset($matches['exponent'])) {
|
||||
$fractional = isset($matches['fractional']) ? $matches['fractional'] : '';
|
||||
$exponent = isset($matches['exponent']) ? (int) $matches['exponent'] : 0;
|
||||
|
||||
$scale = strlen($fractional) - $exponent;
|
||||
$unscaledValue = BigNumber::cleanUp($matches['integral'] . $fractional);
|
||||
|
||||
if ($scale < 0) {
|
||||
if ($unscaledValue !== '0') {
|
||||
$unscaledValue .= str_repeat('0', - $scale);
|
||||
}
|
||||
$scale = 0;
|
||||
$scale = strlen($fractional) - $exponent;
|
||||
|
||||
if ($scale < 0) {
|
||||
if ($unscaledValue !== '0') {
|
||||
$unscaledValue .= str_repeat('0', - $scale);
|
||||
}
|
||||
$scale = 0;
|
||||
}
|
||||
|
||||
$result = new BigDecimal($unscaledValue, $scale);
|
||||
$result = new BigDecimal($unscaledValue, $scale);
|
||||
|
||||
try {
|
||||
switch (static::class) {
|
||||
case BigInteger::class:
|
||||
return $result->toBigInteger();
|
||||
@ -124,24 +142,24 @@ abstract class BigNumber
|
||||
default:
|
||||
return $result;
|
||||
}
|
||||
} else {
|
||||
$integral = BigNumber::cleanUp($matches['integral']);
|
||||
} catch (ArithmeticException $e) {
|
||||
$className = substr(static::class, strrpos(static::class, '\\') + 1);
|
||||
|
||||
switch (static::class) {
|
||||
case BigDecimal::class:
|
||||
return new BigDecimal($integral);
|
||||
|
||||
case BigRational::class:
|
||||
return new BigRational(new BigInteger($integral), new BigInteger('1'), false);
|
||||
|
||||
default:
|
||||
return new BigInteger($integral);
|
||||
}
|
||||
throw new \InvalidArgumentException('Cannot convert value to a ' . $className . ' without losing precision.');
|
||||
}
|
||||
} catch (ArithmeticException $e) {
|
||||
$className = substr(static::class, strrpos(static::class, '\\') + 1);
|
||||
} else {
|
||||
$integral = BigNumber::cleanUp($matches['integral']);
|
||||
|
||||
throw new \InvalidArgumentException('Cannot convert value to a ' . $className . ' without losing precision.');
|
||||
switch (static::class) {
|
||||
case BigDecimal::class:
|
||||
return new BigDecimal($integral);
|
||||
|
||||
case BigRational::class:
|
||||
return new BigRational(new BigInteger($integral), new BigInteger('1'), false);
|
||||
|
||||
default:
|
||||
return new BigInteger($integral);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace Brick\Math;
|
||||
|
||||
use Brick\Math\Exception\ArithmeticException;
|
||||
use Brick\Math\Exception\DivisionByZeroException;
|
||||
|
||||
/**
|
||||
* An arbitrarily large rational number.
|
||||
@ -32,13 +33,13 @@ final class BigRational extends BigNumber implements \Serializable
|
||||
* @param BigInteger $denominator The denominator.
|
||||
* @param bool $checkDemominator Whether to check the denominator for negative and zero.
|
||||
*
|
||||
* @throws ArithmeticException If the denominator is zero.
|
||||
* @throws DivisionByZeroException If the denominator is zero.
|
||||
*/
|
||||
protected function __construct(BigInteger $numerator, BigInteger $denominator, $checkDemominator)
|
||||
{
|
||||
if ($checkDemominator) {
|
||||
if ($denominator->isZero()) {
|
||||
throw new ArithmeticException('The denominator must not be zero.');
|
||||
throw DivisionByZeroException::denominatorMustNotBeZero();
|
||||
}
|
||||
|
||||
if ($denominator->isNegative()) {
|
||||
@ -62,7 +63,7 @@ final class BigRational extends BigNumber implements \Serializable
|
||||
*
|
||||
* @return BigRational
|
||||
*
|
||||
* @throws ArithmeticException If the denominator is zero.
|
||||
* @throws DivisionByZeroException If the denominator is zero.
|
||||
*/
|
||||
public static function nd($numerator, $denominator)
|
||||
{
|
||||
@ -181,7 +182,7 @@ final class BigRational extends BigNumber implements \Serializable
|
||||
*
|
||||
* @return BigRational
|
||||
*
|
||||
* @throws ArithmeticException If the numerator is zero.
|
||||
* @throws DivisionByZeroException If the numerator is zero.
|
||||
*/
|
||||
public function reciprocal()
|
||||
{
|
||||
|
@ -21,14 +21,6 @@ class ArithmeticException extends \RuntimeException
|
||||
return new self(sprintf($message, (string) $value, ~PHP_INT_MAX, PHP_INT_MAX));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArithmeticException
|
||||
*/
|
||||
public static function divisionByZero()
|
||||
{
|
||||
return new self('Division by zero.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArithmeticException
|
||||
*/
|
||||
|
25
src/Exception/DivisionByZeroException.php
Normal file
25
src/Exception/DivisionByZeroException.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Brick\Math\Exception;
|
||||
|
||||
/**
|
||||
* Exception thrown when a division by zero occurs.
|
||||
*/
|
||||
class DivisionByZeroException extends ArithmeticException
|
||||
{
|
||||
/**
|
||||
* @return ArithmeticException
|
||||
*/
|
||||
public static function divisionByZero()
|
||||
{
|
||||
return new self('Division by zero.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DivisionByZeroException
|
||||
*/
|
||||
public static function denominatorMustNotBeZero()
|
||||
{
|
||||
return new DivisionByZeroException('The denominator of a rational number cannot be zero.');
|
||||
}
|
||||
}
|
@ -583,7 +583,7 @@ class BigDecimalTest extends AbstractTestCase
|
||||
|
||||
/**
|
||||
* @dataProvider providerDividedByZeroThrowsException
|
||||
* @expectedException \Brick\Math\Exception\ArithmeticException
|
||||
* @expectedException \Brick\Math\Exception\DivisionByZeroException
|
||||
*
|
||||
* @param string|number $zero
|
||||
*/
|
||||
@ -1289,7 +1289,7 @@ class BigDecimalTest extends AbstractTestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Brick\Math\Exception\ArithmeticException
|
||||
* @expectedException \Brick\Math\Exception\DivisionByZeroException
|
||||
*/
|
||||
public function testDivideAndRemainderByZeroThrowsException()
|
||||
{
|
||||
|
@ -505,7 +505,7 @@ class BigIntegerTest extends AbstractTestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Brick\Math\Exception\ArithmeticException
|
||||
* @expectedException \Brick\Math\Exception\DivisionByZeroException
|
||||
*/
|
||||
public function testDividedByZeroThrowsException()
|
||||
{
|
||||
@ -583,7 +583,7 @@ class BigIntegerTest extends AbstractTestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Brick\Math\Exception\ArithmeticException
|
||||
* @expectedException \Brick\Math\Exception\DivisionByZeroException
|
||||
*/
|
||||
public function testDivideAndRemainderByZeroThrowsException()
|
||||
{
|
||||
|
@ -39,6 +39,14 @@ class BigRationalTest extends AbstractTestCase
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Brick\Math\Exception\DivisionByZeroException
|
||||
*/
|
||||
public function testNdWithZeroDenominator()
|
||||
{
|
||||
BigRational::nd(1, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerOf
|
||||
*
|
||||
@ -69,6 +77,14 @@ class BigRationalTest extends AbstractTestCase
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Brick\Math\Exception\DivisionByZeroException
|
||||
*/
|
||||
public function testOfWithZeroDenominator()
|
||||
{
|
||||
BigRational::of('2/0');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerParseInvalidString
|
||||
* @expectedException \InvalidArgumentException
|
||||
@ -246,7 +262,7 @@ class BigRationalTest extends AbstractTestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Brick\Math\Exception\ArithmeticException
|
||||
* @expectedException \Brick\Math\Exception\DivisionByZeroException
|
||||
*/
|
||||
public function testReciprocalOfZeroThrowsException()
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user