diff --git a/NEWS b/NEWS index bde051dee660..9b5bd7f197e8 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,10 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.4.27 +- BCMath: + . Fixed BcMath\Number results that truncate to zero keeping a negative sign + and comparing less than zero. (Ilia Alshanetsky) + - CLI . Fix GH-22567 (Windows ZTS CLI SAPI should refresh its TSRMLS cache during request activation). (matyhtf) diff --git a/ext/bcmath/bcmath.c b/ext/bcmath/bcmath.c index e54e5bfac774..4bdd8a234237 100644 --- a/ext/bcmath/bcmath.c +++ b/ext/bcmath/bcmath.c @@ -1048,6 +1048,9 @@ static zend_always_inline void bcmath_number_add_internal( } *ret = bc_add(n1, n2, *scale); (*ret)->n_scale = MIN(*scale, (*ret)->n_scale); + if (bc_is_zero(*ret)) { + (*ret)->n_sign = PLUS; + } bc_rm_trailing_zeros(*ret); } @@ -1060,6 +1063,9 @@ static zend_always_inline void bcmath_number_sub_internal( } *ret = bc_sub(n1, n2, *scale); (*ret)->n_scale = MIN(*scale, (*ret)->n_scale); + if (bc_is_zero(*ret)) { + (*ret)->n_sign = PLUS; + } bc_rm_trailing_zeros(*ret); } @@ -1076,6 +1082,9 @@ static zend_always_inline zend_result bcmath_number_mul_internal( } *ret = bc_multiply(n1, n2, *scale); (*ret)->n_scale = MIN(*scale, (*ret)->n_scale); + if (bc_is_zero(*ret)) { + (*ret)->n_sign = PLUS; + } bc_rm_trailing_zeros(*ret); return SUCCESS; } diff --git a/ext/bcmath/libbcmath/src/div.c b/ext/bcmath/libbcmath/src/div.c index ce9ae1e1dd79..a45ffdb77575 100644 --- a/ext/bcmath/libbcmath/src/div.c +++ b/ext/bcmath/libbcmath/src/div.c @@ -349,8 +349,12 @@ bool bc_divide(bc_num numerator, bc_num divisor, bc_num *quot, size_t scale) *quot = bc_new_num_nonzeroed(numerator->n_len, quot_scale); char *qptr = (*quot)->n_value; memcpy(qptr, numerator->n_value, numerator->n_len + quot_scale); - (*quot)->n_sign = numerator->n_sign == divisor->n_sign ? PLUS : MINUS; _bc_rm_leading_zeros(*quot); + if (bc_is_zero(*quot)) { + (*quot)->n_sign = PLUS; + } else { + (*quot)->n_sign = numerator->n_sign == divisor->n_sign ? PLUS : MINUS; + } return true; } @@ -475,7 +479,11 @@ bool bc_divide(bc_num numerator, bc_num divisor, bc_num *quot, size_t scale) for (size_t i = 0; i < numerator_bottom_extension; i++) { *qptr++ = 0; } - (*quot)->n_sign = numerator->n_sign == divisor->n_sign ? PLUS : MINUS; + if (bc_is_zero(*quot)) { + (*quot)->n_sign = PLUS; + } else { + (*quot)->n_sign = numerator->n_sign == divisor->n_sign ? PLUS : MINUS; + } return true; } diff --git a/ext/bcmath/libbcmath/src/raise.c b/ext/bcmath/libbcmath/src/raise.c index 1e283864694b..efb30f24ffce 100644 --- a/ext/bcmath/libbcmath/src/raise.c +++ b/ext/bcmath/libbcmath/src/raise.c @@ -102,6 +102,9 @@ bool bc_raise(bc_num base, long exponent, bc_num *result, size_t scale) { bc_free_num (result); *result = temp; (*result)->n_scale = MIN(scale, (*result)->n_scale); + if (bc_is_zero(*result)) { + (*result)->n_sign = PLUS; + } } bc_free_num (&power); return true; diff --git a/ext/bcmath/tests/number/methods/calc_methods_zero_result_sign.phpt b/ext/bcmath/tests/number/methods/calc_methods_zero_result_sign.phpt new file mode 100644 index 000000000000..1871f0e3ca2c --- /dev/null +++ b/ext/bcmath/tests/number/methods/calc_methods_zero_result_sign.phpt @@ -0,0 +1,35 @@ +--TEST-- +BcMath\Number calc methods return an unsigned zero when the result truncates to zero +--EXTENSIONS-- +bcmath +--FILE-- +$method($arg, $scale); + echo "{$num} {$method} {$arg}: {$ret} ", $ret <=> 0, ' ', var_export($ret == 0, true), "\n"; +} + +[$quot, $rem] = (new BcMath\Number('-0.001'))->divmod('1', 0); +echo "-0.001 divmod 1: {$quot} ", $quot <=> 0, ' ', var_export($quot == 0, true), "\n"; +?> +--EXPECT-- +-0.001 div 1: 0 0 true +0.001 div -1: 0 0 true +-0.001 div 10: 0.00 0 true +-0.001 div 0.1: 0.0 0 true +-0.001 add -0.001: 0 0 true +-0.001 sub 0.001: 0 0 true +-0.001 mul 1: 0 0 true +-0.1 pow 3: 0.00 0 true +-0.001 divmod 1: 0 0 true