From 85aba9377e3fa69d94239cfc557070eaa7aaa26c Mon Sep 17 00:00:00 2001 From: SakiTakamachi Date: Sun, 24 Sep 2023 21:42:06 +0900 Subject: [PATCH 1/5] remove pre-rounding --- ext/standard/math.c | 48 +++-------- ext/standard/tests/math/bug24142.phpt | 74 +++++++++++++---- .../round_gh12143_remove_pre_rounding.phpt | 83 +++++++++++++++++++ .../tests/math/round_prerounding.phpt | 10 --- 4 files changed, 155 insertions(+), 60 deletions(-) create mode 100644 ext/standard/tests/math/round_gh12143_remove_pre_rounding.phpt delete mode 100644 ext/standard/tests/math/round_prerounding.phpt diff --git a/ext/standard/math.c b/ext/standard/math.c index 6b16b0755f69..3546e002b736 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -166,55 +166,31 @@ static inline double php_round_helper(double value, int mode) { /* {{{ _php_math_round */ /* * Rounds a number to a certain number of decimal places in a certain rounding - * mode. For the specifics of the algorithm, see http://wiki.php.net/rfc/rounding + * mode. + * If you "HALF UP" a value like 0.258 (0.28499999999999998), it will be rounded to 28. + * */ PHPAPI double _php_math_round(double value, int places, int mode) { - double f1, f2; + double f1; double tmp_value; - int precision_places; if (!zend_finite(value) || value == 0.0) { return value; } places = places < INT_MIN+1 ? INT_MIN+1 : places; - precision_places = 14 - php_intlog10abs(value); f1 = php_intpow10(abs(places)); - /* If the decimal precision guaranteed by FP arithmetic is higher than - the requested places BUT is small enough to make sure a non-zero value - is returned, pre-round the result to the precision */ - if (precision_places > places && precision_places - 15 < places) { - int64_t use_precision = precision_places < INT_MIN+1 ? INT_MIN+1 : precision_places; - - f2 = php_intpow10(abs((int)use_precision)); - if (use_precision >= 0) { - tmp_value = value * f2; - } else { - tmp_value = value / f2; - } - /* preround the result (tmp_value will always be something * 1e14, - thus never larger than 1e15 here) */ - tmp_value = php_round_helper(tmp_value, mode); - - use_precision = places - precision_places; - use_precision = use_precision < INT_MIN+1 ? INT_MIN+1 : use_precision; - /* now correctly move the decimal point */ - f2 = php_intpow10(abs((int)use_precision)); - /* because places < precision_places */ - tmp_value = tmp_value / f2; + /* adjust the value */ + if (places >= 0) { + tmp_value = value * f1; } else { - /* adjust the value */ - if (places >= 0) { - tmp_value = value * f1; - } else { - tmp_value = value / f1; - } - /* This value is beyond our precision, so rounding it is pointless */ - if (fabs(tmp_value) >= 1e15) { - return value; - } + tmp_value = value / f1; + } + /* This value is beyond our precision, so rounding it is pointless */ + if (fabs(tmp_value) >= 1e15) { + return value; } /* round the temp value */ diff --git a/ext/standard/tests/math/bug24142.phpt b/ext/standard/tests/math/bug24142.phpt index 947deaebd669..739ac25421dc 100644 --- a/ext/standard/tests/math/bug24142.phpt +++ b/ext/standard/tests/math/bug24142.phpt @@ -2,19 +2,65 @@ Bug #24142 (round() problems) --FILE-- ".round($v, 2)."\n"; - $v += 0.01; -} +echo "round(0.005, 2)\n"; +var_dump(round(0.005, 2)); +echo "\n"; + +echo "round(0.015, 2)\n"; +var_dump(round(0.015, 2)); +echo "\n"; + +echo "round(0.025, 2)\n"; +var_dump(round(0.025, 2)); +echo "\n"; + +echo "round(0.035, 2)\n"; +var_dump(round(0.035, 2)); +echo "\n"; + +echo "round(0.045, 2)\n"; +var_dump(round(0.045, 2)); +echo "\n"; + +echo "round(0.055, 2)\n"; +var_dump(round(0.055, 2)); +echo "\n"; + +echo "round(0.065, 2)\n"; +var_dump(round(0.065, 2)); +echo "\n"; + +echo "round(0.075, 2)\n"; +var_dump(round(0.075, 2)); +echo "\n"; + +echo "round(0.085, 2)\n"; +var_dump(round(0.085, 2)); ?> --EXPECT-- -round(0.005, 2) -> 0.01 -round(0.015, 2) -> 0.02 -round(0.025, 2) -> 0.03 -round(0.035, 2) -> 0.04 -round(0.045, 2) -> 0.05 -round(0.055, 2) -> 0.06 -round(0.065, 2) -> 0.07 -round(0.075, 2) -> 0.08 -round(0.085, 2) -> 0.09 +round(0.005, 2) +float(0.01) + +round(0.015, 2) +float(0.02) + +round(0.025, 2) +float(0.03) + +round(0.035, 2) +float(0.04) + +round(0.045, 2) +float(0.05) + +round(0.055, 2) +float(0.06) + +round(0.065, 2) +float(0.07) + +round(0.075, 2) +float(0.08) + +round(0.085, 2) +float(0.09) diff --git a/ext/standard/tests/math/round_gh12143_remove_pre_rounding.phpt b/ext/standard/tests/math/round_gh12143_remove_pre_rounding.phpt new file mode 100644 index 000000000000..fa07a36e6bd3 --- /dev/null +++ b/ext/standard/tests/math/round_gh12143_remove_pre_rounding.phpt @@ -0,0 +1,83 @@ +--TEST-- +Fix GH-12143: Remove pre-rounding +--FILE-- + +--EXPECT-- +HALF_UP +float(1.7000000000001) +float(-1.7000000000001) +float(123456789012340) +float(-123456789012340) +float(0.28) +float(-0.28) + +HALF_DOWN +float(1.7000000000001) +float(-1.7000000000001) +float(123456789012340) +float(-123456789012340) +float(2) +float(-2) +float(1.24) +float(-1.24) + +HALF_EVEN +float(1.7000000000002) +float(-1.7000000000002) +float(1.7000000000008) +float(-1.7000000000008) +float(12345678901234) +float(-12345678901234) +float(2) +float(-2) + +HALF_ODD +float(1.7000000000003) +float(-1.7000000000003) +float(1.7000000000007) +float(-1.7000000000007) +float(12345678901233) +float(-12345678901233) +float(2) +float(-2) diff --git a/ext/standard/tests/math/round_prerounding.phpt b/ext/standard/tests/math/round_prerounding.phpt deleted file mode 100644 index 0419d6c735a4..000000000000 --- a/ext/standard/tests/math/round_prerounding.phpt +++ /dev/null @@ -1,10 +0,0 @@ ---TEST-- -round() prerounds results to precision ---INI-- -precision=14 ---FILE-- - ---EXPECT-- -float(0.29) From 3b22f2409d9841774ea18ad96b1b061afcaca30d Mon Sep 17 00:00:00 2001 From: SakiTakamachi Date: Sun, 24 Sep 2023 21:48:49 +0900 Subject: [PATCH 2/5] fix comment --- ext/standard/math.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ext/standard/math.c b/ext/standard/math.c index 3546e002b736..ddba3ab90ace 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -165,8 +165,7 @@ static inline double php_round_helper(double value, int mode) { /* {{{ _php_math_round */ /* - * Rounds a number to a certain number of decimal places in a certain rounding - * mode. + * Rounds a number to a certain number of decimal places in a certain rounding mode. * If you "HALF UP" a value like 0.258 (0.28499999999999998), it will be rounded to 28. * */ From 09716c3f4461eafe35aed80945ae855f35aa8a4e Mon Sep 17 00:00:00 2001 From: SakiTakamachi Date: Sun, 24 Sep 2023 21:49:04 +0900 Subject: [PATCH 3/5] fix comment --- ext/standard/math.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ext/standard/math.c b/ext/standard/math.c index ddba3ab90ace..1d3d48e064d0 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -167,7 +167,6 @@ static inline double php_round_helper(double value, int mode) { /* * Rounds a number to a certain number of decimal places in a certain rounding mode. * If you "HALF UP" a value like 0.258 (0.28499999999999998), it will be rounded to 28. - * */ PHPAPI double _php_math_round(double value, int places, int mode) { double f1; From 92bf2584f0636d4c998bf1c10fa5838023ed6a5e Mon Sep 17 00:00:00 2001 From: Saki Takamachi <34942839+SakiTakamachi@users.noreply.github.com> Date: Sun, 24 Sep 2023 21:56:38 +0900 Subject: [PATCH 4/5] fix comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tim Düsterhus --- ext/standard/math.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/standard/math.c b/ext/standard/math.c index 1d3d48e064d0..5ecefe6a5645 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -166,7 +166,7 @@ static inline double php_round_helper(double value, int mode) { /* {{{ _php_math_round */ /* * Rounds a number to a certain number of decimal places in a certain rounding mode. - * If you "HALF UP" a value like 0.258 (0.28499999999999998), it will be rounded to 28. + * If you "HALF UP" a value like 0.285 (0.28499999999999998), it will be rounded to 0.28. */ PHPAPI double _php_math_round(double value, int places, int mode) { double f1; From 503887f1292c721a0f64cc6951729e81ed9f780b Mon Sep 17 00:00:00 2001 From: SakiTakamachi Date: Mon, 25 Sep 2023 02:58:55 +0900 Subject: [PATCH 5/5] remove php_intlog10abs --- ext/standard/math.c | 44 -------------------------------------------- 1 file changed, 44 deletions(-) diff --git a/ext/standard/math.c b/ext/standard/math.c index 5ecefe6a5645..30be591e18a4 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -30,50 +30,6 @@ #include "basic_functions.h" -/* {{{ php_intlog10abs - Returns floor(log10(fabs(val))), uses fast binary search */ -static inline int php_intlog10abs(double value) { - value = fabs(value); - - if (value < 1e-8 || value > 1e22) { - return (int)floor(log10(value)); - } else { - /* Do a binary search with 5 steps */ - int result = 15; - static const double values[] = { - 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, - 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, - 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22}; - - if (value < values[result]) { - result -= 8; - } else { - result += 8; - } - if (value < values[result]) { - result -= 4; - } else { - result += 4; - } - if (value < values[result]) { - result -= 2; - } else { - result += 2; - } - if (value < values[result]) { - result -= 1; - } else { - result += 1; - } - if (value < values[result]) { - result -= 1; - } - result -= 8; - return result; - } -} -/* }}} */ - /* {{{ php_intpow10 Returns pow(10.0, (double)power), uses fast lookup table for exact powers */ static inline double php_intpow10(int power) {