Skip to content

Commit

Permalink
Convert RoundingMode to Enum
Browse files Browse the repository at this point in the history
  • Loading branch information
BenMorel committed Aug 1, 2023
1 parent b561137 commit f0b0b4a
Show file tree
Hide file tree
Showing 11 changed files with 67 additions and 92 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file.
💥 **Breaking changes**

- Minimum PHP version is now 8.1
- `RoundingMode` is now an `enum`; if you're type-hinting rounding modes, you need to type-hint against `RoundingMode` instead of `int` now

## [0.11.0](https://github.com/brick/math/releases/tag/0.11.0) - 2023-01-16

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ This library provides the following public classes in the `Brick\Math` namespace
- [BigInteger](https://github.com/brick/math/blob/0.12.0/src/BigInteger.php): represents an arbitrary-precision integer number.
- [BigDecimal](https://github.com/brick/math/blob/0.12.0/src/BigDecimal.php): represents an arbitrary-precision decimal number.
- [BigRational](https://github.com/brick/math/blob/0.12.0/src/BigRational.php): represents an arbitrary-precision rational number (fraction).
- [RoundingMode](https://github.com/brick/math/blob/0.12.0/src/RoundingMode.php): holds constants for the rounding modes.
- [RoundingMode](https://github.com/brick/math/blob/0.12.0/src/RoundingMode.php): enum representing all available rounding modes.

And the following exceptions in the `Brick\Math\Exception` namespace:

Expand Down
6 changes: 3 additions & 3 deletions src/BigDecimal.php
Original file line number Diff line number Diff line change
Expand Up @@ -223,12 +223,12 @@ public function multipliedBy(BigNumber|int|float|string $that) : BigDecimal
*
* @param BigNumber|int|float|string $that The divisor.
* @param int|null $scale The desired scale, or null to use the scale of this number.
* @param int $roundingMode An optional rounding mode.
* @param RoundingMode $roundingMode An optional rounding mode, defaults to UNNECESSARY.
*
* @throws \InvalidArgumentException If the scale or rounding mode is invalid.
* @throws MathException If the number is invalid, is zero, or rounding was necessary.
*/
public function dividedBy(BigNumber|int|float|string $that, ?int $scale = null, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
public function dividedBy(BigNumber|int|float|string $that, ?int $scale = null, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
{
$that = BigDecimal::of($that);

Expand Down Expand Up @@ -631,7 +631,7 @@ public function toBigRational() : BigRational
return self::newBigRational($numerator, $denominator, false);
}

public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
{
if ($scale === $this->scale) {
return $this;
Expand Down
6 changes: 3 additions & 3 deletions src/BigInteger.php
Original file line number Diff line number Diff line change
Expand Up @@ -429,12 +429,12 @@ public function multipliedBy(BigNumber|int|float|string $that) : BigInteger
* Returns the result of the division of this number by the given one.
*
* @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigInteger.
* @param int $roundingMode An optional rounding mode.
* @param RoundingMode $roundingMode An optional rounding mode, defaults to UNNECESSARY.
*
* @throws MathException If the divisor is not a valid number, is not convertible to a BigInteger, is zero,
* or RoundingMode::UNNECESSARY is used and the remainder is not zero.
*/
public function dividedBy(BigNumber|int|float|string $that, int $roundingMode = RoundingMode::UNNECESSARY) : BigInteger
public function dividedBy(BigNumber|int|float|string $that, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigInteger
{
$that = BigInteger::of($that);

Expand Down Expand Up @@ -888,7 +888,7 @@ public function toBigRational() : BigRational
return self::newBigRational($this, BigInteger::one(), false);
}

public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
{
return $this->toBigDecimal()->toScale($scale, $roundingMode);
}
Expand Down
6 changes: 3 additions & 3 deletions src/BigNumber.php
Original file line number Diff line number Diff line change
Expand Up @@ -450,13 +450,13 @@ abstract public function toBigRational() : BigRational;
/**
* Converts this number to a BigDecimal with the given scale, using rounding if necessary.
*
* @param int $scale The scale of the resulting `BigDecimal`.
* @param int $roundingMode A `RoundingMode` constant.
* @param int $scale The scale of the resulting `BigDecimal`.
* @param RoundingMode $roundingMode An optional rounding mode, defaults to UNNECESSARY.
*
* @throws RoundingNecessaryException If this number cannot be converted to the given scale without rounding.
* This only applies when RoundingMode::UNNECESSARY is used.
*/
abstract public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal;
abstract public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal;

/**
* Returns the exact value of this number as a native integer.
Expand Down
2 changes: 1 addition & 1 deletion src/BigRational.php
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ public function toBigRational() : BigRational
return $this;
}

public function toScale(int $scale, int $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
{
return $this->numerator->toBigDecimal()->dividedBy($this->denominator, $scale, $roundingMode);
}
Expand Down
8 changes: 4 additions & 4 deletions src/Internal/Calculator.php
Original file line number Diff line number Diff line change
Expand Up @@ -428,16 +428,16 @@ final public function toArbitraryBase(string $number, string $alphabet, int $bas
*
* Rounding is performed when the remainder of the division is not zero.
*
* @param string $a The dividend.
* @param string $b The divisor, must not be zero.
* @param int $roundingMode The rounding mode.
* @param string $a The dividend.
* @param string $b The divisor, must not be zero.
* @param RoundingMode $roundingMode The rounding mode.
*
* @throws \InvalidArgumentException If the rounding mode is invalid.
* @throws RoundingNecessaryException If RoundingMode::UNNECESSARY is provided but rounding is necessary.
*
* @psalm-suppress ImpureFunctionCall
*/
final public function divRound(string $a, string $b, int $roundingMode) : string
final public function divRound(string $a, string $b, RoundingMode $roundingMode) : string
{
[$quotient, $remainder] = $this->divQR($a, $b);

Expand Down
31 changes: 11 additions & 20 deletions src/RoundingMode.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,85 +13,76 @@
* regardless the digits' contribution to the value of the number. In other words, considered
* as a numerical value, the discarded fraction could have an absolute value greater than one.
*/
final class RoundingMode
enum RoundingMode
{
/**
* Private constructor. This class is not instantiable.
*
* @codeCoverageIgnore
*/
private function __construct()
{
}

/**
* Asserts that the requested operation has an exact result, hence no rounding is necessary.
*
* If this rounding mode is specified on an operation that yields a result that
* cannot be represented at the requested scale, a RoundingNecessaryException is thrown.
*/
public const UNNECESSARY = 0;
case UNNECESSARY;

/**
* Rounds away from zero.
*
* Always increments the digit prior to a nonzero discarded fraction.
* Note that this rounding mode never decreases the magnitude of the calculated value.
*/
public const UP = 1;
case UP;

/**
* Rounds towards zero.
*
* Never increments the digit prior to a discarded fraction (i.e., truncates).
* Note that this rounding mode never increases the magnitude of the calculated value.
*/
public const DOWN = 2;
case DOWN;

/**
* Rounds towards positive infinity.
*
* If the result is positive, behaves as for UP; if negative, behaves as for DOWN.
* Note that this rounding mode never decreases the calculated value.
*/
public const CEILING = 3;
case CEILING;

/**
* Rounds towards negative infinity.
*
* If the result is positive, behave as for DOWN; if negative, behave as for UP.
* Note that this rounding mode never increases the calculated value.
*/
public const FLOOR = 4;
case FLOOR;

/**
* Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round up.
*
* Behaves as for UP if the discarded fraction is >= 0.5; otherwise, behaves as for DOWN.
* Note that this is the rounding mode commonly taught at school.
*/
public const HALF_UP = 5;
case HALF_UP;

/**
* Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round down.
*
* Behaves as for UP if the discarded fraction is > 0.5; otherwise, behaves as for DOWN.
*/
public const HALF_DOWN = 6;
case HALF_DOWN;

/**
* Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round towards positive infinity.
*
* If the result is positive, behaves as for HALF_UP; if negative, behaves as for HALF_DOWN.
*/
public const HALF_CEILING = 7;
case HALF_CEILING;

/**
* Rounds towards "nearest neighbor" unless both neighbors are equidistant, in which case round towards negative infinity.
*
* If the result is positive, behaves as for HALF_DOWN; if negative, behaves as for HALF_UP.
*/
public const HALF_FLOOR = 8;
case HALF_FLOOR;

/**
* Rounds towards the "nearest neighbor" unless both neighbors are equidistant, in which case rounds towards the even neighbor.
Expand All @@ -103,5 +94,5 @@ private function __construct()
* cumulative error when applied repeatedly over a sequence of calculations.
* It is sometimes known as "Banker's rounding", and is chiefly used in the USA.
*/
public const HALF_EVEN = 9;
case HALF_EVEN;
}
58 changes: 26 additions & 32 deletions tests/BigDecimalTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -726,14 +726,14 @@ public static function providerMultipliedBy() : array
/**
* @dataProvider providerDividedBy
*
* @param string $a The base number.
* @param string $b The number to divide.
* @param int|null $scale The desired scale of the result.
* @param int $roundingMode The rounding mode.
* @param string $unscaledValue The expected unscaled value of the result.
* @param int $expectedScale The expected scale of the result.
* @param string $a The base number.
* @param string $b The number to divide.
* @param int|null $scale The desired scale of the result.
* @param RoundingMode $roundingMode The rounding mode.
* @param string $unscaledValue The expected unscaled value of the result.
* @param int $expectedScale The expected scale of the result.
*/
public function testDividedBy(string $a, string $b, ?int $scale, int $roundingMode, string $unscaledValue, int $expectedScale) : void
public function testDividedBy(string $a, string $b, ?int $scale, RoundingMode $roundingMode, string $unscaledValue, int $expectedScale) : void
{
$decimal = BigDecimal::of($a)->dividedBy($b, $scale, $roundingMode);
self::assertBigDecimalInternalValues($unscaledValue, $expectedScale, $decimal);
Expand Down Expand Up @@ -875,22 +875,16 @@ public function testDividedByWithNegativeScaleThrowsException() : void
BigDecimal::of(1)->dividedBy(2, -1);
}

public function testDividedByWithInvalidRoundingModeThrowsException() : void
{
$this->expectException(\InvalidArgumentException::class);
BigDecimal::of(1)->dividedBy(2, 0, -1);
}

/**
* @dataProvider providerRoundingMode
*
* @param int $roundingMode The rounding mode.
* @param string $number The number to round.
* @param string|null $two The expected rounding to a scale of two, or null if an exception is expected.
* @param string|null $one The expected rounding to a scale of one, or null if an exception is expected.
* @param string|null $zero The expected rounding to a scale of zero, or null if an exception is expected.
* @param RoundingMode $roundingMode The rounding mode.
* @param string $number The number to round.
* @param string|null $two The expected rounding to a scale of two, or null if an exception is expected.
* @param string|null $one The expected rounding to a scale of one, or null if an exception is expected.
* @param string|null $zero The expected rounding to a scale of zero, or null if an exception is expected.
*/
public function testRoundingMode(int $roundingMode, string $number, ?string $two, ?string $one, ?string $zero) : void
public function testRoundingMode(RoundingMode $roundingMode, string $number, ?string $two, ?string $one, ?string $zero) : void
{
$number = BigDecimal::of($number);

Expand All @@ -899,14 +893,14 @@ public function testRoundingMode(int $roundingMode, string $number, ?string $two
}

/**
* @param int $roundingMode The rounding mode.
* @param BigDecimal $number The number to round.
* @param string $divisor The divisor.
* @param string|null $two The expected rounding to a scale of two, or null if an exception is expected.
* @param string|null $one The expected rounding to a scale of one, or null if an exception is expected.
* @param string|null $zero The expected rounding to a scale of zero, or null if an exception is expected.
* @param RoundingMode $roundingMode The rounding mode.
* @param BigDecimal $number The number to round.
* @param string $divisor The divisor.
* @param string|null $two The expected rounding to a scale of two, or null if an exception is expected.
* @param string|null $one The expected rounding to a scale of one, or null if an exception is expected.
* @param string|null $zero The expected rounding to a scale of zero, or null if an exception is expected.
*/
private function doTestRoundingMode(int $roundingMode, BigDecimal $number, string $divisor, ?string $two, ?string $one, ?string $zero) : void
private function doTestRoundingMode(RoundingMode $roundingMode, BigDecimal $number, string $divisor, ?string $two, ?string $one, ?string $zero) : void
{
foreach ([$zero, $one, $two] as $scale => $expected) {
if ($expected === null) {
Expand Down Expand Up @@ -1799,13 +1793,13 @@ public static function providerPowerWithInvalidExponentThrowsException() : array
/**
* @dataProvider providerToScale
*
* @param string $number The number to scale.
* @param int $toScale The scale to apply.
* @param int $roundingMode The rounding mode to apply.
* @param string $unscaledValue The expected unscaled value of the result.
* @param int $scale The expected scale of the result.
* @param string $number The number to scale.
* @param int $toScale The scale to apply.
* @param RoundingMode $roundingMode The rounding mode to apply.
* @param string $unscaledValue The expected unscaled value of the result.
* @param int $scale The expected scale of the result.
*/
public function testToScale(string $number, int $toScale, int $roundingMode, string $unscaledValue, int $scale) : void
public function testToScale(string $number, int $toScale, RoundingMode $roundingMode, string $unscaledValue, int $scale) : void
{
$decimal = BigDecimal::of($number)->toScale($toScale, $roundingMode);
self::assertBigDecimalInternalValues($unscaledValue, $scale, $decimal);
Expand Down
32 changes: 13 additions & 19 deletions tests/BigIntegerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -660,22 +660,16 @@ public static function providerDividedBy() : array
];
}

public function testDividedByWithInvalidRoundingModeThrowsException() : void
{
$this->expectException(\InvalidArgumentException::class);
BigInteger::of(1)->dividedBy(2, -1);
}

/**
* @dataProvider providerDividedByWithRoundingMode
*
* @param int $roundingMode The rounding mode.
* @param string $number The number to round.
* @param string|null $ten The expected rounding divided by 10, or null if an exception is expected.
* @param string|null $hundred The expected rounding divided by 100 or null if an exception is expected.
* @param string|null $thousand The expected rounding divided by 1000, or null if an exception is expected.
* @param RoundingMode $roundingMode The rounding mode.
* @param string $number The number to round.
* @param string|null $ten The expected rounding divided by 10, or null if an exception is expected.
* @param string|null $hundred The expected rounding divided by 100 or null if an exception is expected.
* @param string|null $thousand The expected rounding divided by 1000, or null if an exception is expected.
*/
public function testDividedByWithRoundingMode(int $roundingMode, string $number, ?string $ten, ?string $hundred, ?string $thousand) : void
public function testDividedByWithRoundingMode(RoundingMode $roundingMode, string $number, ?string $ten, ?string $hundred, ?string $thousand) : void
{
$number = BigInteger::of($number);

Expand All @@ -684,14 +678,14 @@ public function testDividedByWithRoundingMode(int $roundingMode, string $number,
}

/**
* @param int $roundingMode The rounding mode.
* @param BigInteger $number The number to round.
* @param string $divisor The divisor.
* @param string|null $ten The expected rounding to a scale of two, or null if an exception is expected.
* @param string|null $hundred The expected rounding to a scale of one, or null if an exception is expected.
* @param string|null $thousand The expected rounding to a scale of zero, or null if an exception is expected.
* @param RoundingMode $roundingMode The rounding mode.
* @param BigInteger $number The number to round.
* @param string $divisor The divisor.
* @param string|null $ten The expected rounding to a scale of two, or null if an exception is expected.
* @param string|null $hundred The expected rounding to a scale of one, or null if an exception is expected.
* @param string|null $thousand The expected rounding to a scale of zero, or null if an exception is expected.
*/
private function doTestDividedByWithRoundingMode(int $roundingMode, BigInteger $number, string $divisor, ?string $ten, ?string $hundred, ?string $thousand) : void
private function doTestDividedByWithRoundingMode(RoundingMode $roundingMode, BigInteger $number, string $divisor, ?string $ten, ?string $hundred, ?string $thousand) : void
{
foreach ([$ten, $hundred, $thousand] as $expected) {
$divisor .= '0';
Expand Down
7 changes: 1 addition & 6 deletions tests/BigRationalTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -810,13 +810,8 @@ public static function providerToBigDecimal() : \Generator

/**
* @dataProvider providerToScale
*
* @param string $number
* @param int $scale
* @param int $roundingMode
* @param string $expected
*/
public function testToScale(string $number, int $scale, int $roundingMode, string $expected) : void
public function testToScale(string $number, int $scale, RoundingMode $roundingMode, string $expected) : void
{
$number = BigRational::of($number);

Expand Down

0 comments on commit f0b0b4a

Please sign in to comment.