Skip to content

Commit

Permalink
Merge branch 'PHP-8.4'
Browse files Browse the repository at this point in the history
* PHP-8.4:
  Correctly round rounding mode with zero edge case (#17065)
  • Loading branch information
SakiTakamachi committed Dec 16, 2024
2 parents aff0448 + 52ebdfb commit 0507b83
Show file tree
Hide file tree
Showing 12 changed files with 82 additions and 15 deletions.
48 changes: 46 additions & 2 deletions ext/bcmath/libbcmath/src/round.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions ext/bcmath/tests/bcround_away_from_zero.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions ext/bcmath/tests/bcround_ceiling.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 0 additions & 8 deletions ext/bcmath/tests/bcround_early_return.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions ext/bcmath/tests/bcround_floor.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions ext/bcmath/tests/bcround_half_down.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions ext/bcmath/tests/bcround_half_even.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions ext/bcmath/tests/bcround_half_odd.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions ext/bcmath/tests/bcround_half_up.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions ext/bcmath/tests/bcround_test_helper.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
3 changes: 3 additions & 0 deletions ext/bcmath/tests/bcround_toward_zero.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 9 additions & 5 deletions ext/bcmath/tests/number/methods/round.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ bcmath
<?php
foreach (RoundingMode::cases() as $mode) {
foreach ([
'0',
'0.1',
'-0.1',
'1.0',
Expand All @@ -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) {
Expand Down

0 comments on commit 0507b83

Please sign in to comment.