Skip to content

Commit

Permalink
Adds percentage increase and decrease calculation methods
Browse files Browse the repository at this point in the history
  • Loading branch information
elliotjreed committed Dec 3, 2023
1 parent 03ca7a7 commit 58bf0c2
Show file tree
Hide file tree
Showing 5 changed files with 406 additions and 2 deletions.
40 changes: 40 additions & 0 deletions src/ElliotJReed/Maths/Number.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,44 @@ public function raiseToPowerReduceByModulus(

return $this;
}

/**
* @param \ElliotJReed\Maths\Number|int|float|string $percent the percentage to increase the "base" number by
*
* @return $this
*/
public function increaseByPercentage(self | int | float | string $percent): self
{
$percentAsString = $this->castNumberToString($percent);

$increase = \bcmul(
$this->number,
\bcdiv($percentAsString, '100', $this->precision),
$this->precision
);

$this->number = \bcadd($this->number, $increase, $this->precision);

return $this;
}

/**
* @param \ElliotJReed\Maths\Number|int|float|string $percent the percentage to decrease the "base" number by
*
* @return $this
*/
public function decreaseByPercentage(self | int | float | string $percent): self
{
$percentAsString = $this->castNumberToString($percent);

$increase = \bcmul(
$this->number,
\bcmul(\bcdiv($percentAsString, '100', $this->precision), '-1', $this->precision),
$this->precision
);

$this->number = \bcadd($this->number, $increase, $this->precision);

return $this;
}
}
4 changes: 2 additions & 2 deletions src/ElliotJReed/Maths/NumberFormat.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ abstract class NumberFormat

/**
* @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
* @param int $precision (Optional) The number of digits after the decimal place in the result. Default: 256
*/
public function __construct(self | int | float | string $number = 0, protected readonly int $precision = 64)
public function __construct(self | int | float | string $number = 0, protected readonly int $precision = 256)
{
$this->number = $this->castNumberToString($number);
}
Expand Down
40 changes: 40 additions & 0 deletions src/ElliotJReed/Maths/NumberImmutable.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,4 +166,44 @@ public function raiseToPowerReduceByModulus(

return new self($newNumber, $this->precision);
}

/**
* @param \ElliotJReed\Maths\Number|int|float|string $percent the percentage to increase the "base" number by
*
* @return $this Returns a new instance of \ElliotJReed\Maths\Number
*/
public function increaseByPercentage(self | int | float | string $percent): self
{
$percentAsString = $this->castNumberToString($percent);

$increase = \bcmul(
$this->number,
\bcdiv($percentAsString, '100', $this->precision),
$this->precision
);

$newNumber = \bcadd($this->number, $increase, $this->precision);

return new self($newNumber, $this->precision);
}

/**
* @param \ElliotJReed\Maths\Number|int|float|string $percent the percentage to decrease the "base" number by
*
* @return $this Returns a new instance of \ElliotJReed\Maths\Number
*/
public function decreaseByPercentage(self | int | float | string $percent): self
{
$percentAsString = $this->castNumberToString($percent);

$increase = \bcmul(
$this->number,
\bcmul(\bcdiv($percentAsString, '100', $this->precision), '-1', $this->precision),
$this->precision
);

$newNumber = \bcadd($this->number, $increase, $this->precision);

return new self($newNumber, $this->precision);
}
}
192 changes: 192 additions & 0 deletions tests/ElliotJReed/Maths/NumberImmutableTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1316,4 +1316,196 @@ public function testItThrowsExceptionWhenDecimalPlacesArgumentIsLessThanZeroWhen

$number->roundToDecimalPlaces(-2);
}

public function testItIncreasesBaseNumberByPercentageWhenNumberIsAnInteger(): void
{
$number = new NumberImmutable(100);
$newNumber = $number->increaseByPercentage(10);

$this->assertSame('110', $newNumber->asString());
$this->assertSame(110.0, $newNumber->asFloat());
$this->assertSame(110, $newNumber->asInteger());
$this->assertSame(110, $newNumber->asInteger(\PHP_ROUND_HALF_DOWN));

$this->assertSame('100', $number->asString());
$this->assertSame(100.0, $number->asFloat());
$this->assertSame(100, $number->asInteger());
$this->assertSame(100, $number->asInteger(\PHP_ROUND_HALF_DOWN));
}

public function testItIncreasesBaseNumberByPercentageWhenNumberIsAFloat(): void
{
$number = new NumberImmutable(100.50);
$newNumber = $number->increaseByPercentage(10.125);

$this->assertSame('110.675625', $newNumber->asString());
$this->assertSame(110.675625, $newNumber->asFloat());
$this->assertSame(111, $newNumber->asInteger());
$this->assertSame(111, $newNumber->asInteger(\PHP_ROUND_HALF_DOWN));

$this->assertSame('100.5', $number->asString());
$this->assertSame(100.5, $number->asFloat());
$this->assertSame(101, $number->asInteger());
$this->assertSame(100, $number->asInteger(\PHP_ROUND_HALF_DOWN));
}

public function testItIncreasesBaseNumberByPercentageWhenNumberIsAString(): void
{
$number = new NumberImmutable('100.50');
$newNumber = $number->increaseByPercentage('10.125');

$this->assertSame('110.675625', $newNumber->asString());
$this->assertSame(110.675625, $newNumber->asFloat());
$this->assertSame(111, $newNumber->asInteger());
$this->assertSame(111, $newNumber->asInteger(\PHP_ROUND_HALF_DOWN));

$this->assertSame('100.5', $number->asString());
$this->assertSame(100.5, $number->asFloat());
$this->assertSame(101, $number->asInteger());
$this->assertSame(100, $number->asInteger(\PHP_ROUND_HALF_DOWN));
}

public function testItIncreasesBaseNumberByNegativePercentageWhenNumberIsAnInteger(): void
{
$number = new NumberImmutable(100);
$newNumber = $number->increaseByPercentage(-10);

$this->assertSame('90', $newNumber->asString());
$this->assertSame(90.0, $newNumber->asFloat());
$this->assertSame(90, $newNumber->asInteger());
$this->assertSame(90, $newNumber->asInteger(\PHP_ROUND_HALF_DOWN));

$this->assertSame('100', $number->asString());
$this->assertSame(100.0, $number->asFloat());
$this->assertSame(100, $number->asInteger());
$this->assertSame(100, $number->asInteger(\PHP_ROUND_HALF_DOWN));
}

public function testItIncreasesBaseNumberByNegativePercentageWhenNumberIsAFloat(): void
{
$number = new NumberImmutable(-100.25);
$newNumber = $number->increaseByPercentage(-10.55);

$this->assertSame('-89.673625', $newNumber->asString());
$this->assertSame(-89.673625, $newNumber->asFloat());
$this->assertSame(-90, $newNumber->asInteger());
$this->assertSame(-90, $newNumber->asInteger(\PHP_ROUND_HALF_DOWN));

$this->assertSame('-100.25', $number->asString());
$this->assertSame(-100.25, $number->asFloat());
$this->assertSame(-100, $number->asInteger());
$this->assertSame(-100, $number->asInteger(\PHP_ROUND_HALF_DOWN));
}

public function testItIncreasesBaseNumberByNegativePercentageWhenNumberIsAString(): void
{
$number = new NumberImmutable('100.33');
$newNumber = $number->increaseByPercentage('-10.66');

$this->assertSame('89.634822', $newNumber->asString());
$this->assertSame(89.634822, $newNumber->asFloat());
$this->assertSame(90, $newNumber->asInteger());
$this->assertSame(90, $newNumber->asInteger(\PHP_ROUND_HALF_DOWN));

$this->assertSame('100.33', $number->asString());
$this->assertSame(100.33, $number->asFloat());
$this->assertSame(100, $number->asInteger());
$this->assertSame(100, $number->asInteger(\PHP_ROUND_HALF_DOWN));
}

public function testItDecreasesBaseNumberByPercentageWhenNumberIsAnInteger(): void
{
$number = new NumberImmutable(100);
$newNumber = $number->decreaseByPercentage(10);

$this->assertSame('90', $newNumber->asString());
$this->assertSame(90.0, $newNumber->asFloat());
$this->assertSame(90, $newNumber->asInteger());
$this->assertSame(90, $newNumber->asInteger(\PHP_ROUND_HALF_DOWN));

$this->assertSame('100', $number->asString());
$this->assertSame(100.0, $number->asFloat());
$this->assertSame(100, $number->asInteger());
$this->assertSame(100, $number->asInteger(\PHP_ROUND_HALF_DOWN));
}

public function testItDecreasesBaseNumberByPercentageWhenNumberIsAFloat(): void
{
$number = new NumberImmutable(10.99);
$newNumber = $number->decreaseByPercentage(5.123);

$this->assertSame('10.4269823', $newNumber->asString());
$this->assertSame(10.4269823, $newNumber->asFloat());
$this->assertSame(10, $newNumber->asInteger());
$this->assertSame(10, $newNumber->asInteger(\PHP_ROUND_HALF_DOWN));

$this->assertSame('10.99', $number->asString());
$this->assertSame(10.99, $number->asFloat());
$this->assertSame(11, $number->asInteger());
$this->assertSame(11, $number->asInteger(\PHP_ROUND_HALF_DOWN));
}

public function testItDecreasesBaseNumberByPercentageWhenNumberIsAString(): void
{
$number = new NumberImmutable('10.99');
$newNumber = $number->decreaseByPercentage('5.123');

$this->assertSame('10.4269823', $newNumber->asString());
$this->assertSame(10.4269823, $newNumber->asFloat());
$this->assertSame(10, $newNumber->asInteger());
$this->assertSame(10, $newNumber->asInteger(\PHP_ROUND_HALF_DOWN));

$this->assertSame('10.99', $number->asString());
$this->assertSame(10.99, $number->asFloat());
$this->assertSame(11, $number->asInteger());
$this->assertSame(11, $number->asInteger(\PHP_ROUND_HALF_DOWN));
}

public function testItDecreasesBaseNumberByNegativePercentageWhenNumberIsAnInteger(): void
{
$number = new NumberImmutable(100);
$newNumber = $number->decreaseByPercentage(-10);

$this->assertSame('110', $newNumber->asString());
$this->assertSame(110.0, $newNumber->asFloat());
$this->assertSame(110, $newNumber->asInteger());
$this->assertSame(110, $newNumber->asInteger(\PHP_ROUND_HALF_DOWN));

$this->assertSame('100', $number->asString());
$this->assertSame(100.0, $number->asFloat());
$this->assertSame(100, $number->asInteger());
$this->assertSame(100, $number->asInteger(\PHP_ROUND_HALF_DOWN));
}

public function testItDecreasesBaseNumberByNegativePercentageWhenNumberIsAFloat(): void
{
$number = new NumberImmutable(25.5);
$newNumber = $number->decreaseByPercentage(15.25);

$this->assertSame('21.61125', $newNumber->asString());
$this->assertSame(21.61125, $newNumber->asFloat());
$this->assertSame(22, $newNumber->asInteger());
$this->assertSame(22, $newNumber->asInteger(\PHP_ROUND_HALF_DOWN));

$this->assertSame('25.5', $number->asString());
$this->assertSame(25.5, $number->asFloat());
$this->assertSame(26, $number->asInteger());
$this->assertSame(25, $number->asInteger(\PHP_ROUND_HALF_DOWN));
}

public function testItDecreasesBaseNumberByNegativePercentageWhenNumberIsAString(): void
{
$number = new NumberImmutable('25.5');
$newNumber = $number->decreaseByPercentage('15.25');

$this->assertSame('21.61125', $newNumber->asString());
$this->assertSame(21.61125, $newNumber->asFloat());
$this->assertSame(22, $newNumber->asInteger());
$this->assertSame(22, $newNumber->asInteger(\PHP_ROUND_HALF_DOWN));

$this->assertSame('25.5', $number->asString());
$this->assertSame(25.5, $number->asFloat());
$this->assertSame(26, $number->asInteger());
$this->assertSame(25, $number->asInteger(\PHP_ROUND_HALF_DOWN));
}
}
Loading

0 comments on commit 58bf0c2

Please sign in to comment.