diff --git a/src/Decimal.php b/src/Decimal.php index 87d2ff5..f026f57 100644 --- a/src/Decimal.php +++ b/src/Decimal.php @@ -8,7 +8,7 @@ final class Decimal private $decimal; - public function __construct($key, float $decimal) + public function __construct($key, ?float $decimal) { $this->key = $key; $this->decimal = $decimal; @@ -19,7 +19,7 @@ public function key() return $this->key; } - public function value(): float + public function value(): ?float { return $this->decimal; } diff --git a/src/Definition/NullNumber.php b/src/Definition/NullNumber.php new file mode 100644 index 0000000..1d3b956 --- /dev/null +++ b/src/Definition/NullNumber.php @@ -0,0 +1,28 @@ +key = $key; + $this->quotient = ($part / $total) * $precision; + $this->integer = (int) $this->quotient; + $this->value = $this->integer; + $this->decimal = $this->quotient - $this->integer; + $this->precision = $precision; + } + + public function integer(): int + { + return $this->integer; + } + + public function value(): float + { + // Since the quotient was multiplied by the precision, we need to divide it back. + return $this->value / $this->precision; + } + + public function increment(): void + { + $this->value++; + } + + public function decimal(): float + { + return $this->decimal; + } +} diff --git a/src/Number.php b/src/Number.php deleted file mode 100644 index 491ad7b..0000000 --- a/src/Number.php +++ /dev/null @@ -1,40 +0,0 @@ -key = $key; - $this->quotient = ($part / $total) * $precision; - $this->integer = (int) $this->quotient; - $this->decimal = $this->quotient - $this->integer; - $this->precision = $precision; - } - - public function integer(): int - { - return $this->integer; - } - - public function increase(): void - { - $this->integer++; - } - - public function decimal(): float - { - return $this->decimal; - } -} diff --git a/src/Remainder.php b/src/Remainder.php index 6def1cb..586b639 100644 --- a/src/Remainder.php +++ b/src/Remainder.php @@ -2,6 +2,8 @@ namespace CustomerGauge\Math\Remainder; +use CustomerGauge\Math\Remainder\Definition\NumberFactory; + final class Remainder { private $numbers; @@ -24,7 +26,7 @@ public function round(int $precision): array $decimals = []; foreach ($this->numbers as $key => $number) { - $numberObject = new Number($key, $number, $this->sum, $precision); + $numberObject = NumberFactory::make($key, $number, $this->sum, $precision); $numbers[$key] = $numberObject; @@ -34,21 +36,34 @@ public function round(int $precision): array } usort($decimals, function (Decimal $a, Decimal $b) { - return $b->value() <=> $a->value(); + if ($b->value() > $a->value()) { + return 1; + } + + // If both values are equal, let's try to preserve the exact same order of their original keys. + if ($a->value() == $b->value()) { + return $a->key() > $b->key(); + } + + return -1; }); - $remaining = $precision - $this->accumulatedSumWithoutDecimals; + if ($this->accumulatedSumWithoutDecimals) { + $remaining = $precision - $this->accumulatedSumWithoutDecimals; + } else { + $remaining = 0; + } for ($i = 0; $i < $remaining; $i++) { $key = $decimals[$i]->key(); - $numbers[$key]->increase(); + $numbers[$key]->increment(); } $result = []; foreach ($numbers as $key => $number) { - $result[$key] = $number->integer() / $precision; + $result[$key] = $number->value(); } return $result; diff --git a/tests/RemainderTest.php b/tests/RemainderTest.php index 769354c..88e401a 100644 --- a/tests/RemainderTest.php +++ b/tests/RemainderTest.php @@ -13,7 +13,7 @@ public function test_basic_division() $result = $remainder->round(4); - self::assertSame([1, 0, 0], $result); + self::assertEquals([1, 0, 0], $result); } public function test_division_with_two_numbers() @@ -22,7 +22,7 @@ public function test_division_with_two_numbers() $result = $remainder->round(4); - self::assertSame([0.5, 0.5, 0], $result); + self::assertEquals([0.5, 0.5, 0], $result); } public function test_array_order_is_kept() @@ -31,7 +31,7 @@ public function test_array_order_is_kept() $result = $remainder->round(4); - self::assertSame([0, 0.5, 0.5], $result); + self::assertEquals([0, 0.5, 0.5], $result); } public function test_basic_remainder_decision() @@ -55,4 +55,22 @@ public function test_irrational_numbers() 0.4211 // 0.42105263157894736842105263157895 ], $result); } + + public function test_null_values_will_always_return_null() + { + $remainder = new Remainder([null, null, null]); + + $result = $remainder->round(4); + + self::assertSame([null, null, null], $result); + } + + public function test_null_will_not_receive_increment() + { + $remainder = new Remainder([null, 1, 1, 1]); + + $result = $remainder->round(4); + + self::assertSame([null, 0.3334, 0.3333, 0.3333], $result); + } } \ No newline at end of file