Skip to content

Commit a86fcfb

Browse files
committed
Fix rounding of zend_dval_to_lval
Now rounding is always towards zero; the rounding can be though as if occurring on the original double. Only relevant for the 32-bit long variant.
1 parent 77566ed commit a86fcfb

File tree

2 files changed

+8
-1
lines changed

2 files changed

+8
-1
lines changed

Zend/tests/dval_to_lval_32.phpt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ if (PHP_INT_SIZE != 4)
1515
-3999999999999999475712.,
1616
-3999999999999998951424.,
1717
];
18+
/* see if we're rounding negative numbers right */
19+
$values[] = -2147483649.8;
1820

1921
foreach ($values as $v) {
2022
var_dump((int)$v);
@@ -27,3 +29,4 @@ int(-2055733248)
2729
int(-2055208960)
2830
int(-2054684672)
2931
int(-2054160384)
32+
int(2147483647)

Zend/zend_operators.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ static zend_always_inline long zend_dval_to_lval(double d)
7777

7878
dmod = fmod(d, two_pow_32);
7979
if (dmod < 0) {
80-
dmod += two_pow_32;
80+
/* we're going to make this number positive; call ceil()
81+
* to simulate rounding towards 0 of the negative number */
82+
dmod = ceil(dmod) + two_pow_32;
8183
}
8284
return (long)(unsigned long)dmod;
8385
}
@@ -93,6 +95,8 @@ static zend_always_inline long zend_dval_to_lval(double d)
9395

9496
dmod = fmod(d, two_pow_64);
9597
if (dmod < 0) {
98+
/* no need to call ceil; original double must have had no
99+
* fractional part, hence dmod does not have one either */
96100
dmod += two_pow_64;
97101
}
98102
return (long)(unsigned long)dmod;

0 commit comments

Comments
 (0)