diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Round.php b/src/PhpSpreadsheet/Calculation/MathTrig/Round.php index a573f2afd..0bb4ba2dc 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/Round.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Round.php @@ -10,8 +10,6 @@ class Round { use ArrayEnabled; - private const ROUNDING_ADJUSTMENT = (PHP_VERSION_ID < 80400) ? 0 : 1e-14; - /** * ROUND. * @@ -69,11 +67,22 @@ class Round return 0.0; } + $digitsPlus1 = $digits + 1; if ($number < 0.0) { - return round($number - 0.5 * 0.1 ** $digits + self::ROUNDING_ADJUSTMENT, $digits, PHP_ROUND_HALF_DOWN); + if ($digitsPlus1 < 0) { + return round($number - 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_DOWN); + } + $result = sprintf("%.{$digitsPlus1}f", $number - 0.5 * 0.1 ** $digits); + + return round((float) $result, $digits, PHP_ROUND_HALF_DOWN); } - return round($number + 0.5 * 0.1 ** $digits - self::ROUNDING_ADJUSTMENT, $digits, PHP_ROUND_HALF_DOWN); + if ($digitsPlus1 < 0) { + return round($number + 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_DOWN); + } + $result = sprintf("%.{$digitsPlus1}f", $number + 0.5 * 0.1 ** $digits); + + return round((float) $result, $digits, PHP_ROUND_HALF_DOWN); } /** @@ -105,11 +114,23 @@ class Round return 0.0; } + $digitsPlus1 = $digits + 1; if ($number < 0.0) { - return round($number + 0.5 * 0.1 ** $digits - self::ROUNDING_ADJUSTMENT, $digits, PHP_ROUND_HALF_UP); + if ($digitsPlus1 < 0) { + return round($number + 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_UP); + } + $result = sprintf("%.{$digitsPlus1}f", $number + 0.5 * 0.1 ** $digits); + + return round((float) $result, $digits, PHP_ROUND_HALF_UP); } - return round($number - 0.5 * 0.1 ** $digits + self::ROUNDING_ADJUSTMENT, $digits, PHP_ROUND_HALF_UP); + if ($digitsPlus1 < 0) { + return round($number - 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_UP); + } + + $result = sprintf("%.{$digitsPlus1}f", $number - 0.5 * 0.1 ** $digits); + + return round((float) $result, $digits, PHP_ROUND_HALF_UP); } /** diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Trunc.php b/src/PhpSpreadsheet/Calculation/MathTrig/Trunc.php index 44aedd2ca..5f3fa8a38 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/Trunc.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Trunc.php @@ -34,15 +34,26 @@ class Trunc return $e->getMessage(); } - $digits = floor($digits); - - // Truncate - $adjust = 10 ** $digits; - - if (($digits > 0) && (rtrim((string) (int) ((abs($value) - abs((int) $value)) * $adjust), '0') < $adjust / 10)) { + if ($value == 0) { return $value; } - return ((int) ($value * $adjust)) / $adjust; + if ($value >= 0) { + $minusSign = ''; + } else { + $minusSign = '-'; + $value = -$value; + } + $digits = (int) floor($digits); + if ($digits < 0) { + $power = (int) (10 ** -$digits); + $result = intdiv((int) floor($value), $power) * $power; + + return ($minusSign === '') ? $result : -$result; + } + $digitsPlus1 = $digits + 1; + $result = substr($minusSign . sprintf("%.{$digitsPlus1}f", $value), 0, -1); + + return (float) $result; } } diff --git a/tests/data/Calculation/MathTrig/ROUNDDOWN.php b/tests/data/Calculation/MathTrig/ROUNDDOWN.php index 3a65c13f2..fed45cd44 100644 --- a/tests/data/Calculation/MathTrig/ROUNDDOWN.php +++ b/tests/data/Calculation/MathTrig/ROUNDDOWN.php @@ -33,4 +33,5 @@ return [ [0, 'B1, 0'], ['exception', ''], ['exception', '35.51'], + 'negative number and precision' => [-31400, '-31415.92654, -2'], ]; diff --git a/tests/data/Calculation/MathTrig/ROUNDUP.php b/tests/data/Calculation/MathTrig/ROUNDUP.php index 9014a9e3c..9683d54d4 100644 --- a/tests/data/Calculation/MathTrig/ROUNDUP.php +++ b/tests/data/Calculation/MathTrig/ROUNDUP.php @@ -33,4 +33,5 @@ return [ [0, 'B1, 0'], ['exception', ''], ['exception', '35.51'], + 'negative number and precision' => [-31500, '-31415.92654, -2'], ]; diff --git a/tests/data/Calculation/MathTrig/TRUNC.php b/tests/data/Calculation/MathTrig/TRUNC.php index 40fa52160..882996d2b 100644 --- a/tests/data/Calculation/MathTrig/TRUNC.php +++ b/tests/data/Calculation/MathTrig/TRUNC.php @@ -11,6 +11,7 @@ return [ [-31415.92654, '-31415.92654, 10'], [31415.92, '31415.92654, 2'], [31400, '31415.92654, -2'], + 'negative number and precision' => [-31400, '-31415.92654, -2'], [0, '31415.92654, -10'], [0, '-31415.92654, -10'], [12000, '12345.6789, -3'], @@ -32,4 +33,12 @@ return [ [-3, 'A4'], [-5, 'A5'], [0, 'B1'], + 'issue4113' => [1.0, '1.01, 1'], + 'issue4113 negative' => [-1.0, '-1.01, 1'], + 'issue4113 additional' => [10.04, '10.04, 2'], + 'issue4113 additional negative' => [-10.04, '-10.04, 2'], + 'issue4113 small fraction keep all' => [0.04, '0.04, 2'], + 'issue4113 small negative fraction keep all' => [-0.04, '-0.04, 2'], + 'issue4113 small fraction lose some' => [0.0, '0.01, 1'], + 'issue4113 small negative fraction lose some' => [0.0, '-0.001, 1'], ];