Correctly round rounding mode with zero edge case (#17065)
Fixes #17064 Closes #17065
This commit is contained in:
2
NEWS
2
NEWS
@ -6,6 +6,8 @@ PHP NEWS
|
||||
. Fixed bug GH-17049 (Correctly compare 0 and -0). (Saki Takamachi)
|
||||
. Fixed bug GH-17061 (Now Number::round() does not remove trailing zeros).
|
||||
(Saki Takamachi)
|
||||
. Fixed bug GH-17064 (Correctly round rounding mode with zero edge case).
|
||||
(Saki Takamachi)
|
||||
|
||||
- Core:
|
||||
. Fixed bug OSS-Fuzz #382922236 (Duplicate dynamic properties in hooked object
|
||||
|
@ -33,10 +33,54 @@ void bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result)
|
||||
* - If the fractional part ends with zeros, the zeros are omitted and the number of digits in num is reduced.
|
||||
* Meaning we might end up in the previous case.
|
||||
*/
|
||||
|
||||
/* e.g. value is 0.1 and precision is -3, ret is 0 or 1000 */
|
||||
if (precision < 0 && num->n_len < (size_t) (-(precision + Z_L(1))) + 1) {
|
||||
*result = bc_copy_num(BCG(_zero_));
|
||||
switch (mode) {
|
||||
case PHP_ROUND_HALF_UP:
|
||||
case PHP_ROUND_HALF_DOWN:
|
||||
case PHP_ROUND_HALF_EVEN:
|
||||
case PHP_ROUND_HALF_ODD:
|
||||
case PHP_ROUND_TOWARD_ZERO:
|
||||
*result = bc_copy_num(BCG(_zero_));
|
||||
return;
|
||||
|
||||
case PHP_ROUND_CEILING:
|
||||
if (num->n_sign == MINUS) {
|
||||
*result = bc_copy_num(BCG(_zero_));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case PHP_ROUND_FLOOR:
|
||||
if (num->n_sign == PLUS) {
|
||||
*result = bc_copy_num(BCG(_zero_));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case PHP_ROUND_AWAY_FROM_ZERO:
|
||||
break;
|
||||
|
||||
EMPTY_SWITCH_DEFAULT_CASE()
|
||||
}
|
||||
|
||||
if (bc_is_zero(num)) {
|
||||
*result = bc_copy_num(BCG(_zero_));
|
||||
return;
|
||||
}
|
||||
|
||||
/* If precision is -3, it becomes 1000. */
|
||||
if (UNEXPECTED(precision == ZEND_LONG_MIN)) {
|
||||
*result = bc_new_num((size_t) ZEND_LONG_MAX + 2, 0);
|
||||
} else {
|
||||
*result = bc_new_num(-precision + 1, 0);
|
||||
}
|
||||
(*result)->n_value[0] = 1;
|
||||
(*result)->n_sign = num->n_sign;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Just like bcadd('1', '1', 4) becomes '2.0000', it pads with zeros at the end if necessary. */
|
||||
if (precision >= 0 && num->n_scale <= precision) {
|
||||
if (num->n_scale == precision) {
|
||||
@ -61,7 +105,7 @@ void bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result)
|
||||
* If the result of rounding is carried over, it will be added later, so first set it to 0 here.
|
||||
*/
|
||||
if (rounded_len == 0) {
|
||||
*result = bc_copy_num(BCG(_zero_));
|
||||
*result = bc_new_num(1, 0);
|
||||
} else {
|
||||
*result = bc_new_num(num->n_len, precision > 0 ? precision : 0);
|
||||
memcpy((*result)->n_value, num->n_value, rounded_len);
|
||||
|
@ -27,6 +27,9 @@ run_round_test(RoundingMode::AwayFromZero);
|
||||
[-1.9, 0] => -2
|
||||
|
||||
========== minus precision ==========
|
||||
[0, -3] => 0
|
||||
[0.01, -3] => 1000
|
||||
[-0.01, -3] => -1000
|
||||
[50, -2] => 100
|
||||
[-50, -2] => -100
|
||||
[1230, -1] => 1230
|
||||
|
@ -27,6 +27,9 @@ run_round_test(RoundingMode::PositiveInfinity);
|
||||
[-1.9, 0] => -1
|
||||
|
||||
========== minus precision ==========
|
||||
[0, -3] => 0
|
||||
[0.01, -3] => 1000
|
||||
[-0.01, -3] => 0
|
||||
[50, -2] => 100
|
||||
[-50, -2] => 0
|
||||
[1230, -1] => 1230
|
||||
|
@ -6,15 +6,11 @@ bcmath
|
||||
<?php
|
||||
|
||||
$early_return_cases = [
|
||||
['123', -4],
|
||||
['123.123456', -4],
|
||||
['123', 1],
|
||||
['123.5', 1],
|
||||
['123.5', 2],
|
||||
['123.0000000000000000000001', 22],
|
||||
['123.0000000000000000000001', 23],
|
||||
['-123', -4],
|
||||
['-123.123456', -4],
|
||||
['-123', 1],
|
||||
['-123.5', 1],
|
||||
['-123.5', 2],
|
||||
@ -54,15 +50,11 @@ foreach (RoundingMode::cases() as $mode) {
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
[123, -4] => 0
|
||||
[123.123456, -4] => 0
|
||||
[123, 1] => 123.0
|
||||
[123.5, 1] => 123.5
|
||||
[123.5, 2] => 123.50
|
||||
[123.0000000000000000000001, 22] => 123.0000000000000000000001
|
||||
[123.0000000000000000000001, 23] => 123.00000000000000000000010
|
||||
[-123, -4] => 0
|
||||
[-123.123456, -4] => 0
|
||||
[-123, 1] => -123.0
|
||||
[-123.5, 1] => -123.5
|
||||
[-123.5, 2] => -123.50
|
||||
|
@ -27,6 +27,9 @@ run_round_test(RoundingMode::NegativeInfinity);
|
||||
[-1.9, 0] => -2
|
||||
|
||||
========== minus precision ==========
|
||||
[0, -3] => 0
|
||||
[0.01, -3] => 0
|
||||
[-0.01, -3] => -1000
|
||||
[50, -2] => 0
|
||||
[-50, -2] => -100
|
||||
[1230, -1] => 1230
|
||||
|
@ -27,6 +27,9 @@ run_round_test(RoundingMode::HalfTowardsZero);
|
||||
[-1.9, 0] => -2
|
||||
|
||||
========== minus precision ==========
|
||||
[0, -3] => 0
|
||||
[0.01, -3] => 0
|
||||
[-0.01, -3] => 0
|
||||
[50, -2] => 0
|
||||
[-50, -2] => 0
|
||||
[1230, -1] => 1230
|
||||
|
@ -27,6 +27,9 @@ run_round_test(RoundingMode::HalfEven);
|
||||
[-1.9, 0] => -2
|
||||
|
||||
========== minus precision ==========
|
||||
[0, -3] => 0
|
||||
[0.01, -3] => 0
|
||||
[-0.01, -3] => 0
|
||||
[50, -2] => 0
|
||||
[-50, -2] => 0
|
||||
[1230, -1] => 1230
|
||||
|
@ -27,6 +27,9 @@ run_round_test(RoundingMode::HalfOdd);
|
||||
[-1.9, 0] => -2
|
||||
|
||||
========== minus precision ==========
|
||||
[0, -3] => 0
|
||||
[0.01, -3] => 0
|
||||
[-0.01, -3] => 0
|
||||
[50, -2] => 100
|
||||
[-50, -2] => -100
|
||||
[1230, -1] => 1230
|
||||
|
@ -27,6 +27,9 @@ run_round_test(RoundingMode::HalfAwayFromZero);
|
||||
[-1.9, 0] => -2
|
||||
|
||||
========== minus precision ==========
|
||||
[0, -3] => 0
|
||||
[0.01, -3] => 0
|
||||
[-0.01, -3] => 0
|
||||
[50, -2] => 100
|
||||
[-50, -2] => -100
|
||||
[1230, -1] => 1230
|
||||
|
@ -30,6 +30,9 @@ function run_round_test(RoundingMode $mode)
|
||||
];
|
||||
|
||||
$minus_precision_cases = [
|
||||
['0', -3],
|
||||
['0.01', -3],
|
||||
['-0.01', -3],
|
||||
['50', -2],
|
||||
['-50', -2],
|
||||
['1230', -1],
|
||||
|
@ -27,6 +27,9 @@ run_round_test(RoundingMode::TowardsZero);
|
||||
[-1.9, 0] => -1
|
||||
|
||||
========== minus precision ==========
|
||||
[0, -3] => 0
|
||||
[0.01, -3] => 0
|
||||
[-0.01, -3] => 0
|
||||
[50, -2] => 0
|
||||
[-50, -2] => 0
|
||||
[1230, -1] => 1230
|
||||
|
@ -6,6 +6,7 @@ bcmath
|
||||
<?php
|
||||
foreach (RoundingMode::cases() as $mode) {
|
||||
foreach ([
|
||||
'0',
|
||||
'0.1',
|
||||
'-0.1',
|
||||
'1.0',
|
||||
@ -19,17 +20,20 @@ foreach (RoundingMode::cases() as $mode) {
|
||||
'2.5',
|
||||
'-2.5',
|
||||
] as $number) {
|
||||
$func_ret = bcround($number, 0, $mode);
|
||||
$method_ret = (new BcMath\Number($number))->round(0, $mode);
|
||||
if ($method_ret->compare($func_ret) !== 0) {
|
||||
echo "Result is incorrect.\n";
|
||||
var_dump($number, $mode, $func_ret, $method_ret);
|
||||
foreach ([0, 5, -5] as $scale) {
|
||||
$func_ret = bcround($number, $scale, $mode);
|
||||
$method_ret = (new BcMath\Number($number))->round($scale, $mode);
|
||||
if ($method_ret->compare($func_ret) !== 0) {
|
||||
echo "Result is incorrect.\n";
|
||||
var_dump($number, $mode, $func_ret, $method_ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (RoundingMode::cases() as $mode) {
|
||||
foreach ([
|
||||
'0',
|
||||
'1.2345678',
|
||||
'-1.2345678',
|
||||
] as $number) {
|
||||
|
Reference in New Issue
Block a user