Skip to content

Commit 85aba93

Browse files
committed
remove pre-rounding
1 parent 0a8ff0b commit 85aba93

File tree

4 files changed

+155
-60
lines changed

4 files changed

+155
-60
lines changed

ext/standard/math.c

Lines changed: 12 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -166,55 +166,31 @@ static inline double php_round_helper(double value, int mode) {
166166
/* {{{ _php_math_round */
167167
/*
168168
* Rounds a number to a certain number of decimal places in a certain rounding
169-
* mode. For the specifics of the algorithm, see http://wiki.php.net/rfc/rounding
169+
* mode.
170+
* If you "HALF UP" a value like 0.258 (0.28499999999999998), it will be rounded to 28.
171+
*
170172
*/
171173
PHPAPI double _php_math_round(double value, int places, int mode) {
172-
double f1, f2;
174+
double f1;
173175
double tmp_value;
174-
int precision_places;
175176

176177
if (!zend_finite(value) || value == 0.0) {
177178
return value;
178179
}
179180

180181
places = places < INT_MIN+1 ? INT_MIN+1 : places;
181-
precision_places = 14 - php_intlog10abs(value);
182182

183183
f1 = php_intpow10(abs(places));
184184

185-
/* If the decimal precision guaranteed by FP arithmetic is higher than
186-
the requested places BUT is small enough to make sure a non-zero value
187-
is returned, pre-round the result to the precision */
188-
if (precision_places > places && precision_places - 15 < places) {
189-
int64_t use_precision = precision_places < INT_MIN+1 ? INT_MIN+1 : precision_places;
190-
191-
f2 = php_intpow10(abs((int)use_precision));
192-
if (use_precision >= 0) {
193-
tmp_value = value * f2;
194-
} else {
195-
tmp_value = value / f2;
196-
}
197-
/* preround the result (tmp_value will always be something * 1e14,
198-
thus never larger than 1e15 here) */
199-
tmp_value = php_round_helper(tmp_value, mode);
200-
201-
use_precision = places - precision_places;
202-
use_precision = use_precision < INT_MIN+1 ? INT_MIN+1 : use_precision;
203-
/* now correctly move the decimal point */
204-
f2 = php_intpow10(abs((int)use_precision));
205-
/* because places < precision_places */
206-
tmp_value = tmp_value / f2;
185+
/* adjust the value */
186+
if (places >= 0) {
187+
tmp_value = value * f1;
207188
} else {
208-
/* adjust the value */
209-
if (places >= 0) {
210-
tmp_value = value * f1;
211-
} else {
212-
tmp_value = value / f1;
213-
}
214-
/* This value is beyond our precision, so rounding it is pointless */
215-
if (fabs(tmp_value) >= 1e15) {
216-
return value;
217-
}
189+
tmp_value = value / f1;
190+
}
191+
/* This value is beyond our precision, so rounding it is pointless */
192+
if (fabs(tmp_value) >= 1e15) {
193+
return value;
218194
}
219195

220196
/* round the temp value */

ext/standard/tests/math/bug24142.phpt

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,65 @@
22
Bug #24142 (round() problems)
33
--FILE--
44
<?php
5-
$v = 0.005;
6-
for ($i = 1; $i < 10; $i++) {
7-
echo "round({$v}, 2) -> ".round($v, 2)."\n";
8-
$v += 0.01;
9-
}
5+
echo "round(0.005, 2)\n";
6+
var_dump(round(0.005, 2));
7+
echo "\n";
8+
9+
echo "round(0.015, 2)\n";
10+
var_dump(round(0.015, 2));
11+
echo "\n";
12+
13+
echo "round(0.025, 2)\n";
14+
var_dump(round(0.025, 2));
15+
echo "\n";
16+
17+
echo "round(0.035, 2)\n";
18+
var_dump(round(0.035, 2));
19+
echo "\n";
20+
21+
echo "round(0.045, 2)\n";
22+
var_dump(round(0.045, 2));
23+
echo "\n";
24+
25+
echo "round(0.055, 2)\n";
26+
var_dump(round(0.055, 2));
27+
echo "\n";
28+
29+
echo "round(0.065, 2)\n";
30+
var_dump(round(0.065, 2));
31+
echo "\n";
32+
33+
echo "round(0.075, 2)\n";
34+
var_dump(round(0.075, 2));
35+
echo "\n";
36+
37+
echo "round(0.085, 2)\n";
38+
var_dump(round(0.085, 2));
1039
?>
1140
--EXPECT--
12-
round(0.005, 2) -> 0.01
13-
round(0.015, 2) -> 0.02
14-
round(0.025, 2) -> 0.03
15-
round(0.035, 2) -> 0.04
16-
round(0.045, 2) -> 0.05
17-
round(0.055, 2) -> 0.06
18-
round(0.065, 2) -> 0.07
19-
round(0.075, 2) -> 0.08
20-
round(0.085, 2) -> 0.09
41+
round(0.005, 2)
42+
float(0.01)
43+
44+
round(0.015, 2)
45+
float(0.02)
46+
47+
round(0.025, 2)
48+
float(0.03)
49+
50+
round(0.035, 2)
51+
float(0.04)
52+
53+
round(0.045, 2)
54+
float(0.05)
55+
56+
round(0.055, 2)
57+
float(0.06)
58+
59+
round(0.065, 2)
60+
float(0.07)
61+
62+
round(0.075, 2)
63+
float(0.08)
64+
65+
round(0.085, 2)
66+
float(0.09)
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
--TEST--
2+
Fix GH-12143: Remove pre-rounding
3+
--FILE--
4+
<?php
5+
echo "HALF_UP\n";
6+
var_dump(round(1.700000000000145, 13, PHP_ROUND_HALF_UP));
7+
var_dump(round(-1.700000000000145, 13, PHP_ROUND_HALF_UP));
8+
var_dump(round(123456789012344.5, -1, PHP_ROUND_HALF_UP));
9+
var_dump(round(-123456789012344.5, -1, PHP_ROUND_HALF_UP));
10+
var_dump (round (0.285, 2, PHP_ROUND_HALF_UP));
11+
var_dump (round (-0.285, 2, PHP_ROUND_HALF_UP));
12+
echo "\n";
13+
14+
echo "HALF_DOWN\n";
15+
var_dump(round(1.70000000000015, 13, PHP_ROUND_HALF_DOWN));
16+
var_dump(round(-1.70000000000015, 13, PHP_ROUND_HALF_DOWN));
17+
var_dump(round(123456789012345.0, -1, PHP_ROUND_HALF_DOWN));
18+
var_dump(round(-123456789012345.0, -1, PHP_ROUND_HALF_DOWN));
19+
var_dump(round(1.500000000000001, 0, PHP_ROUND_HALF_DOWN));
20+
var_dump(round(-1.500000000000001, 0, PHP_ROUND_HALF_DOWN));
21+
var_dump (round (1.235, 2, PHP_ROUND_HALF_UP));
22+
var_dump (round (-1.235, 2, PHP_ROUND_HALF_UP));
23+
echo "\n";
24+
25+
echo "HALF_EVEN\n";
26+
var_dump(round(1.70000000000025, 13, PHP_ROUND_HALF_EVEN));
27+
var_dump(round(-1.70000000000025, 13, PHP_ROUND_HALF_EVEN));
28+
var_dump(round(1.70000000000075, 13, PHP_ROUND_HALF_EVEN));
29+
var_dump(round(-1.70000000000075, 13, PHP_ROUND_HALF_EVEN));
30+
var_dump(round(12345678901234.5, 0, PHP_ROUND_HALF_EVEN));
31+
var_dump(round(-12345678901234.5, 0, PHP_ROUND_HALF_EVEN));
32+
var_dump(round(1.500000000000001, 0, PHP_ROUND_HALF_EVEN));
33+
var_dump(round(-1.500000000000001, 0, PHP_ROUND_HALF_EVEN));
34+
echo "\n";
35+
36+
echo "HALF_ODD\n";
37+
var_dump(round(1.70000000000025, 13, PHP_ROUND_HALF_ODD));
38+
var_dump(round(-1.70000000000025, 13, PHP_ROUND_HALF_ODD));
39+
var_dump(round(1.70000000000075, 13, PHP_ROUND_HALF_ODD));
40+
var_dump(round(-1.70000000000075, 13, PHP_ROUND_HALF_ODD));
41+
var_dump(round(12345678901233.5, 0, PHP_ROUND_HALF_ODD));
42+
var_dump(round(-12345678901233.5, 0, PHP_ROUND_HALF_ODD));
43+
var_dump(round(1.500000000000001, 0, PHP_ROUND_HALF_ODD));
44+
var_dump(round(-1.500000000000001, 0, PHP_ROUND_HALF_ODD));
45+
?>
46+
--EXPECT--
47+
HALF_UP
48+
float(1.7000000000001)
49+
float(-1.7000000000001)
50+
float(123456789012340)
51+
float(-123456789012340)
52+
float(0.28)
53+
float(-0.28)
54+
55+
HALF_DOWN
56+
float(1.7000000000001)
57+
float(-1.7000000000001)
58+
float(123456789012340)
59+
float(-123456789012340)
60+
float(2)
61+
float(-2)
62+
float(1.24)
63+
float(-1.24)
64+
65+
HALF_EVEN
66+
float(1.7000000000002)
67+
float(-1.7000000000002)
68+
float(1.7000000000008)
69+
float(-1.7000000000008)
70+
float(12345678901234)
71+
float(-12345678901234)
72+
float(2)
73+
float(-2)
74+
75+
HALF_ODD
76+
float(1.7000000000003)
77+
float(-1.7000000000003)
78+
float(1.7000000000007)
79+
float(-1.7000000000007)
80+
float(12345678901233)
81+
float(-12345678901233)
82+
float(2)
83+
float(-2)

ext/standard/tests/math/round_prerounding.phpt

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
 (0)