Skip to content

Commit

Permalink
Extracts common functionality to abstract class
Browse files Browse the repository at this point in the history
  • Loading branch information
elliotjreed committed Dec 2, 2023
1 parent e44147e commit bc74c0e
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 273 deletions.
138 changes: 1 addition & 137 deletions src/ElliotJReed/Maths/Number.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,63 +8,8 @@
use ElliotJReed\Maths\Exception\InvalidExponent;
use ElliotJReed\Maths\Exception\InvalidPowerModulusDivisor;

final class Number
final class Number extends NumberFormat
{
protected string $number;

/**
* @param \ElliotJReed\Maths\Number|int|float|string $number (Optional) The "base" number. Default: 0
* @param int $precision (Optional) The number of digits after the decimal place in the result. Default: 64
*/
public function __construct(self | int | float | string $number = 0, private readonly int $precision = 64)
{
$this->number = $this->castNumberToString($number);
}

/**
* @param int|null $decimalPlaces (Optional) The number of decimal places to return (note: this will not round the number, for rounding use the roundToDecimalPlaces method)
* @param string $thousandsSeparator (Optional) Thousands separator. Default: empty string (i.e. none)
*
* @return string the number formatted as a string
*
* @throws \ElliotJReed\Maths\Exception\InvalidDecimalPlaces thrown when the decimal places argument is less than zero
*/
public function asString(?int $decimalPlaces = null, string $thousandsSeparator = ''): string
{
if (null !== $decimalPlaces) {
if ($decimalPlaces < 0) {
throw new InvalidDecimalPlaces('Decimal places must be a whole number greater than or equal to 0. Invalid decimal places number: ' . $decimalPlaces);
}

return \number_format((float) $this->number, $decimalPlaces, '.', $thousandsSeparator);
}

$number = $this->number;
if (\str_contains($this->number, '.')) {
$number = \rtrim($this->number, '0');
}

return \rtrim($number, '.') ?: '0';
}

/**
* @return float the number formatted as a float (decimal)
*/
public function asFloat(): float
{
return (float) $this->number;
}

/**
* @param int $roundingMode (Optional) The rounding method defined by PHP internal maths constants [PHP_ROUND_HALF_UP (1) | PHP_ROUND_HALF_DOWN (2) | PHP_ROUND_HALF_EVEN (3) | PHP_ROUND_HALF_ODD (4)]. Default: PHP_ROUND_HALF_UP (1)
*
* @return int the number formatted as an integer (rounded up by default)
*/
public function asInteger(int $roundingMode = \PHP_ROUND_HALF_UP): int
{
return (int) \round((float) $this->number, mode: $roundingMode);
}

/**
* @param int $decimalPlaces the number of decimal places to round to
* @param int $roundingMode (Optional) The rounding method defined by PHP internal maths constants [PHP_ROUND_HALF_UP (1) | PHP_ROUND_HALF_DOWN (2) | PHP_ROUND_HALF_EVEN (3) | PHP_ROUND_HALF_ODD (4)]. Default: PHP_ROUND_HALF_UP (1)
Expand Down Expand Up @@ -219,85 +164,4 @@ public function raiseToPowerReduceByModulus(

return $this;
}

/**
* @param \ElliotJReed\Maths\Number|int|float|string $number the comparator number
*
* @return bool returns true when the comparator number is less than the base number, or false when the comparator number is greater than or equal to the "base" number
*/
public function isLessThan(self | int | float | string $number): bool
{
$numberAsString = $this->castNumberToString($number);

$result = \bccomp($this->number, $numberAsString, $this->precision);

return -1 === $result;
}

/**
* @param \ElliotJReed\Maths\Number|int|float|string $number the comparator number
*
* @return bool returns true when the comparator number is greater than the base number, or false when the comparator number is less than or equal to the "base" number
*/
public function isGreaterThan(self | int | float | string $number): bool
{
$numberAsString = $this->castNumberToString($number);

$result = \bccomp($this->number, $numberAsString, $this->precision);

return 1 === $result;
}

/**
* @param \ElliotJReed\Maths\Number|int|float|string $number the comparator number
*
* @return bool returns true when the comparator number is equal to the base number, or false when the comparator number is less than or greater than the "base" number
*/
public function isEqualTo(self | int | float | string $number): bool
{
$numberAsString = $this->castNumberToString($number);

$result = \bccomp($this->number, $numberAsString, $this->precision);

return 0 === $result;
}

/**
* @param \ElliotJReed\Maths\Number|int|float|string $number the comparator number
*
* @return bool returns true when the comparator number is less than or equal to the base number, or false when the comparator number is greater than the "base" number
*/
public function isLessThanOrEqualTo(self | int | float | string $number): bool
{
$numberAsString = $this->castNumberToString($number);

$result = \bccomp($this->number, $numberAsString, $this->precision);

return -1 === $result || 0 === $result;
}

/**
* @param \ElliotJReed\Maths\Number|int|float|string $number the comparator number
*
* @return bool returns true when the comparator number is greater than or equal to the base number, or false when the comparator number is less than the "base" number
*/
public function isGreaterThanOrEqualTo(self | int | float | string $number): bool
{
$numberAsString = $this->castNumberToString($number);

$result = \bccomp($this->number, $numberAsString, $this->precision);

return 1 === $result || 0 === $result;
}

private function castNumberToString(self | int | float | string $number): string
{
if ($number instanceof self) {
$numberAsString = $number->asString();
} else {
$numberAsString = (string) $number;
}

return $numberAsString;
}
}
146 changes: 146 additions & 0 deletions src/ElliotJReed/Maths/NumberFormat.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<?php

declare(strict_types=1);

namespace ElliotJReed\Maths;

use ElliotJReed\Maths\Exception\InvalidDecimalPlaces;

abstract class NumberFormat
{
protected string $number;

/**
* @param \ElliotJReed\Maths\Number|int|float|string $number (Optional) The "base" number. Default: 0
* @param int $precision (Optional) The number of digits after the decimal place in the result. Default: 64
*/
public function __construct(self | int | float | string $number = 0, protected readonly int $precision = 64)
{
$this->number = $this->castNumberToString($number);
}

/**
* @param int|null $decimalPlaces (Optional) The number of decimal places to return (note: this will not round the number, for rounding use the roundToDecimalPlaces method)
* @param string $thousandsSeparator (Optional) Thousands separator. Default: empty string (i.e. none)
*
* @return string the number formatted as a string
*
* @throws \ElliotJReed\Maths\Exception\InvalidDecimalPlaces thrown when the decimal places argument is less than zero
*/
public function asString(?int $decimalPlaces = null, string $thousandsSeparator = ''): string
{
if (null !== $decimalPlaces) {
if ($decimalPlaces < 0) {
throw new InvalidDecimalPlaces('Decimal places must be a whole number greater than or equal to 0. Invalid decimal places number: ' . $decimalPlaces);
}

return \number_format((float) $this->number, $decimalPlaces, '.', $thousandsSeparator);
}

$number = $this->number;
if (\str_contains($this->number, '.')) {
$number = \rtrim($this->number, '0');
}

return \rtrim($number, '.') ?: '0';
}

/**
* @return float the number formatted as a float (decimal)
*/
public function asFloat(): float
{
return (float) $this->number;
}

/**
* @param int $roundingMode (Optional) The rounding method defined by PHP internal maths constants [PHP_ROUND_HALF_UP (1) | PHP_ROUND_HALF_DOWN (2) | PHP_ROUND_HALF_EVEN (3) | PHP_ROUND_HALF_ODD (4)]. Default: PHP_ROUND_HALF_UP (1)
*
* @return int the number formatted as an integer (rounded up by default)
*/
public function asInteger(int $roundingMode = \PHP_ROUND_HALF_UP): int
{
return (int) \round((float) $this->number, mode: $roundingMode);
}

/**
* @param \ElliotJReed\Maths\Number|int|float|string $number the comparator number
*
* @return bool returns true when the comparator number is less than the base number, or false when the comparator number is greater than or equal to the "base" number
*/
public function isLessThan(self | int | float | string $number): bool
{
$numberAsString = $this->castNumberToString($number);

$result = \bccomp($this->number, $numberAsString, $this->precision);

return -1 === $result;
}

/**
* @param \ElliotJReed\Maths\Number|int|float|string $number the comparator number
*
* @return bool returns true when the comparator number is greater than the base number, or false when the comparator number is less than or equal to the "base" number
*/
public function isGreaterThan(self | int | float | string $number): bool
{
$numberAsString = $this->castNumberToString($number);

$result = \bccomp($this->number, $numberAsString, $this->precision);

return 1 === $result;
}

/**
* @param \ElliotJReed\Maths\Number|int|float|string $number the comparator number
*
* @return bool returns true when the comparator number is equal to the base number, or false when the comparator number is less than or greater than the "base" number
*/
public function isEqualTo(self | int | float | string $number): bool
{
$numberAsString = $this->castNumberToString($number);

$result = \bccomp($this->number, $numberAsString, $this->precision);

return 0 === $result;
}

/**
* @param \ElliotJReed\Maths\Number|int|float|string $number the comparator number
*
* @return bool returns true when the comparator number is less than or equal to the base number, or false when the comparator number is greater than the "base" number
*/
public function isLessThanOrEqualTo(self | int | float | string $number): bool
{
$numberAsString = $this->castNumberToString($number);

$result = \bccomp($this->number, $numberAsString, $this->precision);

return -1 === $result || 0 === $result;
}

/**
* @param \ElliotJReed\Maths\Number|int|float|string $number the comparator number
*
* @return bool returns true when the comparator number is greater than or equal to the base number, or false when the comparator number is less than the "base" number
*/
public function isGreaterThanOrEqualTo(self | int | float | string $number): bool
{
$numberAsString = $this->castNumberToString($number);

$result = \bccomp($this->number, $numberAsString, $this->precision);

return 1 === $result || 0 === $result;
}

protected function castNumberToString(self | int | float | string $number): string
{
if ($number instanceof self) {
$numberAsString = $number->asString();
} else {
$numberAsString = (string) $number;
}

return $numberAsString;
}
}
Loading

0 comments on commit bc74c0e

Please sign in to comment.