diff --git a/NEWS b/NEWS index f941ce90e47f1..bd7c6b3a26ae0 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,7 @@ PHP NEWS - BCMath: . Simplify `bc_divide()` code. (SakiTakamachi) + . If the result is 0, n_scale is set to 0. (SakiTakamachi) - CLI: . Add --ini=diff to print INI settings changed from the builtin default. diff --git a/ext/bcmath/bcmath.c b/ext/bcmath/bcmath.c index 233045bd7cd7e..962f839ba83f4 100644 --- a/ext/bcmath/bcmath.c +++ b/ext/bcmath/bcmath.c @@ -807,8 +807,8 @@ PHP_FUNCTION(bcround) goto cleanup; } - bc_round(num, precision, mode, &result); - RETVAL_NEW_STR(bc_num2str_ex(result, result->n_scale)); + size_t scale = bc_round(num, precision, mode, &result); + RETVAL_NEW_STR(bc_num2str_ex(result, scale)); cleanup: { bc_free_num(&num); @@ -1799,9 +1799,10 @@ PHP_METHOD(BcMath_Number, round) bcmath_number_obj_t *intern = get_bcmath_number_from_zval(ZEND_THIS); bc_num ret = NULL; - bc_round(intern->num, precision, rounding_mode, &ret); + size_t scale = bc_round(intern->num, precision, rounding_mode, &ret); + bc_rm_trailing_zeros(ret); - bcmath_number_obj_t *new_intern = bcmath_number_new_obj(ret, ret->n_scale); + bcmath_number_obj_t *new_intern = bcmath_number_new_obj(ret, scale); RETURN_OBJ(&new_intern->std); } diff --git a/ext/bcmath/libbcmath/src/bcmath.h b/ext/bcmath/libbcmath/src/bcmath.h index f7e14019bd336..1f05ad51f7f26 100644 --- a/ext/bcmath/libbcmath/src/bcmath.h +++ b/ext/bcmath/libbcmath/src/bcmath.h @@ -157,7 +157,7 @@ bool bc_divmod(bc_num num1, bc_num num2, bc_num *quo, bc_num *rem, size_t scale) bc_num bc_floor_or_ceil(bc_num num, bool is_floor); -void bc_round(bc_num num, zend_long places, zend_long mode, bc_num *result); +size_t bc_round(bc_num num, zend_long places, zend_long mode, bc_num *result); typedef enum { OK, diff --git a/ext/bcmath/libbcmath/src/div.c b/ext/bcmath/libbcmath/src/div.c index cda452569dedc..ec7619fb77090 100644 --- a/ext/bcmath/libbcmath/src/div.c +++ b/ext/bcmath/libbcmath/src/div.c @@ -430,6 +430,7 @@ bool bc_divide(bc_num numerator, bc_num divisor, bc_num *quot, size_t scale) _bc_rm_leading_zeros(*quot); if (bc_is_zero(*quot)) { (*quot)->n_sign = PLUS; + (*quot)->n_scale = 0; } else { (*quot)->n_sign = numerator->n_sign == divisor->n_sign ? PLUS : MINUS; } diff --git a/ext/bcmath/libbcmath/src/divmod.c b/ext/bcmath/libbcmath/src/divmod.c index 294a281b2e687..477ec30e916ea 100644 --- a/ext/bcmath/libbcmath/src/divmod.c +++ b/ext/bcmath/libbcmath/src/divmod.c @@ -74,6 +74,7 @@ bool bc_divmod(bc_num num1, bc_num num2, bc_num *quot, bc_num *rem, size_t scale (*rem)->n_scale = MIN(scale, (*rem)->n_scale); if (bc_is_zero(*rem)) { (*rem)->n_sign = PLUS; + (*rem)->n_scale = 0; } return true; diff --git a/ext/bcmath/libbcmath/src/recmul.c b/ext/bcmath/libbcmath/src/recmul.c index b92a1045ac3b5..de06a4ca037ec 100644 --- a/ext/bcmath/libbcmath/src/recmul.c +++ b/ext/bcmath/libbcmath/src/recmul.c @@ -264,6 +264,7 @@ bc_num bc_multiply(bc_num n1, bc_num n2, size_t scale) _bc_rm_leading_zeros(prod); if (bc_is_zero(prod)) { prod->n_sign = PLUS; + prod->n_scale = 0; } return prod; } diff --git a/ext/bcmath/libbcmath/src/round.c b/ext/bcmath/libbcmath/src/round.c index ac3c7c41a315e..44df6036cbe3b 100644 --- a/ext/bcmath/libbcmath/src/round.c +++ b/ext/bcmath/libbcmath/src/round.c @@ -18,7 +18,8 @@ #include "private.h" #include -void bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result) +/* Returns the scale of the value after rounding. */ +size_t bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result) { /* clear result */ bc_free_num(result); @@ -43,19 +44,19 @@ void bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result) case PHP_ROUND_HALF_ODD: case PHP_ROUND_TOWARD_ZERO: *result = bc_copy_num(BCG(_zero_)); - return; + return 0; case PHP_ROUND_CEILING: if (num->n_sign == MINUS) { *result = bc_copy_num(BCG(_zero_)); - return; + return 0; } break; case PHP_ROUND_FLOOR: if (num->n_sign == PLUS) { *result = bc_copy_num(BCG(_zero_)); - return; + return 0; } break; @@ -67,7 +68,7 @@ void bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result) if (bc_is_zero(num)) { *result = bc_copy_num(BCG(_zero_)); - return; + return 0; } /* If precision is -3, it becomes 1000. */ @@ -78,7 +79,7 @@ void bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result) } (*result)->n_value[0] = 1; (*result)->n_sign = num->n_sign; - return; + return 0; } /* Just like bcadd('1', '1', 4) becomes '2.0000', it pads with zeros at the end if necessary. */ @@ -90,7 +91,7 @@ void bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result) (*result)->n_sign = num->n_sign; memcpy((*result)->n_value, num->n_value, num->n_len + num->n_scale); } - return; + return precision; } /* @@ -222,7 +223,12 @@ void bc_round(bc_num num, zend_long precision, zend_long mode, bc_num *result) } check_zero: - if (bc_is_zero(*result)) { - (*result)->n_sign = PLUS; + { + size_t scale = (*result)->n_scale; + if (bc_is_zero(*result)) { + (*result)->n_sign = PLUS; + (*result)->n_scale = 0; + } + return scale; } }