From 6c474eb817128a5bbbe5047bc844383cd739e8cd Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Fri, 8 Sep 2023 23:32:31 +0200 Subject: [PATCH 1/5] Change precision of rounding for large FP numbers: --- ext/standard/math.c | 14 ++++++++------ ext/standard/tests/math/round_bug12143.phpt | 10 ++++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 ext/standard/tests/math/round_bug12143.phpt diff --git a/ext/standard/math.c b/ext/standard/math.c index 74ffa565031a3..d4883b0f78886 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -97,7 +97,8 @@ static inline double php_round_helper(double value, int mode) { if (value >= 0.0) { tmp_value = floor(value + 0.5); - if ((mode == PHP_ROUND_HALF_DOWN && value == (-0.5 + tmp_value)) || + if ((mode == PHP_ROUND_HALF_UP && value < (-0.5 + tmp_value)) || + (mode == PHP_ROUND_HALF_DOWN && value == (-0.5 + tmp_value)) || (mode == PHP_ROUND_HALF_EVEN && value == (0.5 + 2 * floor(tmp_value/2.0))) || (mode == PHP_ROUND_HALF_ODD && value == (0.5 + 2 * floor(tmp_value/2.0) - 1.0))) { @@ -105,7 +106,8 @@ static inline double php_round_helper(double value, int mode) { } } else { tmp_value = ceil(value - 0.5); - if ((mode == PHP_ROUND_HALF_DOWN && value == (0.5 + tmp_value)) || + if ((mode == PHP_ROUND_HALF_UP && value > (0.5 + tmp_value)) || + (mode == PHP_ROUND_HALF_DOWN && value == (0.5 + tmp_value)) || (mode == PHP_ROUND_HALF_EVEN && value == (-0.5 + 2 * ceil(tmp_value/2.0))) || (mode == PHP_ROUND_HALF_ODD && value == (-0.5 + 2 * ceil(tmp_value/2.0) + 1.0))) { @@ -131,7 +133,7 @@ PHPAPI double _php_math_round(double value, int places, int mode) { return value; } - places = places < INT_MIN+1 ? INT_MIN+1 : places; + places = places < INT_MIN + 1 ? INT_MIN + 1 : places; precision_places = 14 - php_intlog10abs(value); f1 = php_intpow10(abs(places)); @@ -139,8 +141,8 @@ PHPAPI double _php_math_round(double value, int places, int mode) { /* 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; + if (precision_places - 1 > 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) { @@ -153,7 +155,7 @@ PHPAPI double _php_math_round(double value, int places, int mode) { 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; + 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 */ diff --git a/ext/standard/tests/math/round_bug12143.phpt b/ext/standard/tests/math/round_bug12143.phpt new file mode 100644 index 0000000000000..aef3b2a7631ce --- /dev/null +++ b/ext/standard/tests/math/round_bug12143.phpt @@ -0,0 +1,10 @@ +--TEST-- +Bug #12143 round with large precision +--FILE-- + +--EXPECT-- +bool(true) +bool(true) From efd8e7d13254b8eb87bead4a5741d2b99b5ec715 Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Sat, 9 Sep 2023 00:16:52 +0200 Subject: [PATCH 2/5] Fix rounding for large precision FP numbers for PHP_ROUND --- ext/standard/math.c | 4 ++-- ext/standard/tests/math/round_bug12143.phpt | 14 +++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/ext/standard/math.c b/ext/standard/math.c index d4883b0f78886..2612c09ebb0f8 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -98,7 +98,7 @@ static inline double php_round_helper(double value, int mode) { if (value >= 0.0) { tmp_value = floor(value + 0.5); if ((mode == PHP_ROUND_HALF_UP && value < (-0.5 + tmp_value)) || - (mode == PHP_ROUND_HALF_DOWN && value == (-0.5 + tmp_value)) || + (mode == PHP_ROUND_HALF_DOWN && value <= (-0.5 + tmp_value)) || (mode == PHP_ROUND_HALF_EVEN && value == (0.5 + 2 * floor(tmp_value/2.0))) || (mode == PHP_ROUND_HALF_ODD && value == (0.5 + 2 * floor(tmp_value/2.0) - 1.0))) { @@ -107,7 +107,7 @@ static inline double php_round_helper(double value, int mode) { } else { tmp_value = ceil(value - 0.5); if ((mode == PHP_ROUND_HALF_UP && value > (0.5 + tmp_value)) || - (mode == PHP_ROUND_HALF_DOWN && value == (0.5 + tmp_value)) || + (mode == PHP_ROUND_HALF_DOWN && value >= (0.5 + tmp_value)) || (mode == PHP_ROUND_HALF_EVEN && value == (-0.5 + 2 * ceil(tmp_value/2.0))) || (mode == PHP_ROUND_HALF_ODD && value == (-0.5 + 2 * ceil(tmp_value/2.0) + 1.0))) { diff --git a/ext/standard/tests/math/round_bug12143.phpt b/ext/standard/tests/math/round_bug12143.phpt index aef3b2a7631ce..33a5f0e7bc87c 100644 --- a/ext/standard/tests/math/round_bug12143.phpt +++ b/ext/standard/tests/math/round_bug12143.phpt @@ -1,10 +1,22 @@ --TEST-- -Bug #12143 round with large precision +Bug #12143 round() with large FP --FILE-- --EXPECT-- bool(true) bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) From 112d9d4d10586b5e97eb625b5baca773242a657e Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Sat, 9 Sep 2023 00:31:29 +0200 Subject: [PATCH 3/5] Improve the rounding for FP numbers for modes PHP_ROUND_HALF_ODD and PHP_ROUND_HALF_EVEN --- ext/standard/math.c | 12 ++++++------ ext/standard/tests/math/round_bug12143.phpt | 18 +++++++++++++++++- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/ext/standard/math.c b/ext/standard/math.c index 2612c09ebb0f8..f32df7dbbc2d9 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -97,19 +97,19 @@ static inline double php_round_helper(double value, int mode) { if (value >= 0.0) { tmp_value = floor(value + 0.5); - if ((mode == PHP_ROUND_HALF_UP && value < (-0.5 + tmp_value)) || - (mode == PHP_ROUND_HALF_DOWN && value <= (-0.5 + tmp_value)) || + if ((mode == PHP_ROUND_HALF_DOWN && value == (-0.5 + tmp_value)) || (mode == PHP_ROUND_HALF_EVEN && value == (0.5 + 2 * floor(tmp_value/2.0))) || - (mode == PHP_ROUND_HALF_ODD && value == (0.5 + 2 * floor(tmp_value/2.0) - 1.0))) + (mode == PHP_ROUND_HALF_ODD && value == (0.5 + 2 * floor(tmp_value/2.0) - 1.0)) || + value < (-0.5 + tmp_value)) { tmp_value = tmp_value - 1.0; } } else { tmp_value = ceil(value - 0.5); - if ((mode == PHP_ROUND_HALF_UP && value > (0.5 + tmp_value)) || - (mode == PHP_ROUND_HALF_DOWN && value >= (0.5 + tmp_value)) || + if ((mode == PHP_ROUND_HALF_DOWN && value == (0.5 + tmp_value)) || (mode == PHP_ROUND_HALF_EVEN && value == (-0.5 + 2 * ceil(tmp_value/2.0))) || - (mode == PHP_ROUND_HALF_ODD && value == (-0.5 + 2 * ceil(tmp_value/2.0) + 1.0))) + (mode == PHP_ROUND_HALF_ODD && value == (-0.5 + 2 * ceil(tmp_value/2.0) + 1.0)) || + value > (0.5 + tmp_value)) { tmp_value = tmp_value + 1.0; } diff --git a/ext/standard/tests/math/round_bug12143.phpt b/ext/standard/tests/math/round_bug12143.phpt index 33a5f0e7bc87c..ec17032e309f7 100644 --- a/ext/standard/tests/math/round_bug12143.phpt +++ b/ext/standard/tests/math/round_bug12143.phpt @@ -4,12 +4,20 @@ Bug #12143 round() with large FP --EXPECT-- bool(true) @@ -20,3 +28,11 @@ bool(true) bool(true) bool(true) bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) From f762b8b68f7fc5038317ee70cda012bcf021ea0e Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Sat, 9 Sep 2023 16:15:22 +0200 Subject: [PATCH 4/5] Removed changes to prerounding --- ext/standard/math.c | 2 +- ext/standard/tests/math/round_bug12143.phpt | 16 ---------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/ext/standard/math.c b/ext/standard/math.c index f32df7dbbc2d9..46a777e16399f 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -141,7 +141,7 @@ PHPAPI double _php_math_round(double value, int places, int mode) { /* 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 - 1 > places && precision_places - 15 < places) { + 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)); diff --git a/ext/standard/tests/math/round_bug12143.phpt b/ext/standard/tests/math/round_bug12143.phpt index ec17032e309f7..8b767af7889ef 100644 --- a/ext/standard/tests/math/round_bug12143.phpt +++ b/ext/standard/tests/math/round_bug12143.phpt @@ -10,14 +10,6 @@ var_dump(round(-0.49999999999999994, 0, PHP_ROUND_HALF_UP) == -0); var_dump(round(-0.49999999999999994, 0, PHP_ROUND_HALF_DOWN) == 0); var_dump(round(-0.49999999999999994, 0, PHP_ROUND_HALF_EVEN) == 0); var_dump(round(-0.49999999999999994, 0, PHP_ROUND_HALF_ODD) == 0); -var_dump(round(1.700000000000145, 13, PHP_ROUND_HALF_UP) == 1.7000000000001); -var_dump(round(1.700000000000145, 13, PHP_ROUND_HALF_DOWN) == 1.7000000000001); -var_dump(round(1.700000000000145, 13, PHP_ROUND_HALF_EVEN) == 1.7000000000001); -var_dump(round(1.700000000000145, 13, PHP_ROUND_HALF_ODD) == 1.7000000000001); -var_dump(round(-1.700000000000145, 13, PHP_ROUND_HALF_UP) == -1.7000000000001); -var_dump(round(-1.700000000000145, 13, PHP_ROUND_HALF_DOWN) == -1.7000000000001); -var_dump(round(-1.700000000000145, 13, PHP_ROUND_HALF_EVEN) == -1.7000000000001); -var_dump(round(-1.700000000000145, 13, PHP_ROUND_HALF_ODD) == -1.7000000000001); ?> --EXPECT-- bool(true) @@ -28,11 +20,3 @@ bool(true) bool(true) bool(true) bool(true) -bool(true) -bool(true) -bool(true) -bool(true) -bool(true) -bool(true) -bool(true) -bool(true) From f043c1025650995f13723db12b186b5142dee149 Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Sun, 10 Sep 2023 11:37:01 +0200 Subject: [PATCH 5/5] Added more numbers to test --- ext/standard/tests/math/round_bug12143.phpt | 48 ++++++++++++++------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/ext/standard/tests/math/round_bug12143.phpt b/ext/standard/tests/math/round_bug12143.phpt index 8b767af7889ef..25797a36100e9 100644 --- a/ext/standard/tests/math/round_bug12143.phpt +++ b/ext/standard/tests/math/round_bug12143.phpt @@ -2,21 +2,37 @@ Bug #12143 round() with large FP --FILE-- --EXPECT-- -bool(true) -bool(true) -bool(true) -bool(true) -bool(true) -bool(true) -bool(true) -bool(true) +float(0) +float(0) +float(0) +float(0) +float(0) +float(0) +float(0) +float(0) +float(1) +float(1) +float(1) +float(1) +float(-1) +float(-1) +float(-1) +float(-1)