Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"require-dev": {
"php-collective/code-sniffer": "^0.2.1",
"phpstan/phpstan": "^2.0.0",
"phpunit/phpunit": "^11.0.0"
"phpunit/phpunit": "^10.5.45 || ^11.0.0"
},
"minimum-stability": "stable",
"prefer-stable": true,
Expand Down
2 changes: 1 addition & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ parameters:
ignoreErrors:
- identifier: missingType.iterableValue
- '#Unsafe usage of new static\(\).#'
- '#expects numeric-string, string given.#'
- '#expects numeric-string, .*string given.#'
34 changes: 28 additions & 6 deletions src/Decimal.php
Original file line number Diff line number Diff line change
Expand Up @@ -485,22 +485,44 @@ public function round(int $scale = 0, int $roundMode = self::ROUND_HALF_UP): sta
{
$exponent = $scale + 1;

$e = bcpow('10', (string)$exponent);
switch ($roundMode) {
case static::ROUND_FLOOR:
$v = bcdiv(bcadd(bcmul((string)$this, $e, 0), $this->isNegative() ? '-9' : '0'), $e, 0);
$stringValue = (string)$this;

break;
// If already an integer, return as is
if (!str_contains($stringValue, '.')) {
return new static($stringValue, $scale);
}

// For positive values, truncate the decimal part (round down)
if (!$this->isNegative()) {
return new static(bcsub($stringValue, bcmod($stringValue, '1'), 0), $scale);
}

// For negative values, round down away from zero
return new static(bcsub($stringValue, '1', 0), $scale);
case static::ROUND_CEIL:
$v = bcdiv(bcadd(bcmul((string)$this, $e, 0), $this->isNegative() ? '0' : '9'), $e, 0);
$stringValue = (string)$this;

// If already an integer, return as is
if (!str_contains($stringValue, '.')) {
return new static($stringValue, $scale);
}

// If negative, truncate (remove decimals without adding 1)
if ($this->isNegative()) {
return new static(bcsub($stringValue, '0', 0), $scale);
}

break;
// Otherwise, round up for positive numbers
return new static(bcadd($stringValue, '1', 0), $scale);
case static::ROUND_HALF_UP:
default:
$e = bcpow('10', (string)$exponent);
$v = bcdiv(bcadd(bcmul((string)$this, $e, 0), $this->isNegative() ? '-5' : '5'), $e, $scale);
}

return new static($v);
return new static($v, $scale);
}

/**
Expand Down
28 changes: 25 additions & 3 deletions tests/DecimalTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,12 @@ public function testRound(mixed $value, int $scale, string $expected): void
*/
protected function assertNativeRound(string $expected, mixed $value, int $scale, int $roundMode): void
{
$this->assertSame((new Decimal($expected))->trim()->toString(), (string)round((float)$value, $scale, $roundMode));
$value = (string)round((float)$value, $scale, $roundMode);
if ($value === '-0') {
$value = '0';
}

$this->assertSame((new Decimal($expected))->trim()->toString(), $value);
}

/**
Expand All @@ -659,6 +664,10 @@ public static function roundProvider(): array
[13.4999, 0, '13'],
[13.4999, 10, '13.4999000000'],
[13.4999, 2, '13.50'],
[0.0001, 0, '0'],
[-0.0001, 0, '0'],
[0.9999, 0, '1'],
[-0.9999, 0, '-1'],
];
}

Expand All @@ -685,7 +694,12 @@ public function testFloor(mixed $value, string $expected): void
*/
protected function assertNativeFloor(string $expected, mixed $value): void
{
$this->assertSame($expected, (string)floor((float)$value));
$value = (string)floor((float)$value);
if ($value === '-0') {
$value = '0';
}

$this->assertSame($expected, $value);
}

/**
Expand All @@ -706,6 +720,8 @@ public static function floorProvider(): array
['13.6999', '13'],
['13.1', '13'],
['13.9', '13'],
[0.0001, '0'],
[-0.0001, '-1'],
];
}

Expand All @@ -732,7 +748,11 @@ public function testCeil(mixed $value, string $expected): void
*/
protected function assertNativeCeil(string $expected, mixed $value): void
{
$this->assertSame($expected, (string)ceil((float)$value));
$value = (string)ceil((float)$value);
if ($value === '-0') {
$value = '0';
}
$this->assertSame($expected, $value);
}

/**
Expand All @@ -753,6 +773,8 @@ public static function ceilProvider(): array
['13.6999', '14'],
['13.1', '14'],
['13.9', '14'],
[0.0001, '1'],
[-0.0001, '0'],
];
}

Expand Down