Skip to content

Commit

Permalink
Merge branch 'dval_to_lval' into PHP-5.5
Browse files Browse the repository at this point in the history
* dval_to_lval:
  Fix rounding of zend_dval_to_lval
  Fix zend_dval_to_lval outside 64bit integers range
  • Loading branch information
cataphract committed Feb 23, 2013
2 parents 64a2a8a + a86fcfb commit 8718755
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 6 deletions.
2 changes: 2 additions & 0 deletions Zend/tests/bug39018.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ print "\nDone\n";
--EXPECTF--
Notice: String offset cast occurred in %s on line %d

Notice: Uninitialized string offset: %s in %s on line 6

Notice: Uninitialized string offset: 0 in %s on line %d

Notice: Uninitialized string offset: 0 in %s on line %d
Expand Down
32 changes: 32 additions & 0 deletions Zend/tests/dval_to_lval_32.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
--TEST--
zend_dval_to_lval preserves low bits (32 bit long)
--SKIPIF--
<?php
if (PHP_INT_SIZE != 4)
die("skip for machines with 32-bit longs");
?>
--FILE--
<?php
/* test doubles around -4e21 */
$values = [
-4000000000000001048576.,
-4000000000000000524288.,
-4000000000000000000000.,
-3999999999999999475712.,
-3999999999999998951424.,
];
/* see if we're rounding negative numbers right */
$values[] = -2147483649.8;

foreach ($values as $v) {
var_dump((int)$v);
}

?>
--EXPECT--
int(-2056257536)
int(-2055733248)
int(-2055208960)
int(-2054684672)
int(-2054160384)
int(2147483647)
29 changes: 29 additions & 0 deletions Zend/tests/dval_to_lval_64.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
--TEST--
zend_dval_to_lval preserves low bits (64 bit long)
--SKIPIF--
<?php
if (PHP_INT_SIZE != 8)
die("skip for machines with 64-bit longs");
?>
--FILE--
<?php
/* test doubles around -4e21 */
$values = [
-4000000000000001048576.,
-4000000000000000524288.,
-4000000000000000000000.,
-3999999999999999475712.,
-3999999999999998951424.,
];

foreach ($values as $v) {
var_dump((int)$v);
}

?>
--EXPECT--
int(2943463994971652096)
int(2943463994972176384)
int(2943463994972700672)
int(2943463994973224960)
int(2943463994973749248)
30 changes: 24 additions & 6 deletions Zend/zend_operators.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,22 +68,40 @@ END_EXTERN_C()

#if ZEND_DVAL_TO_LVAL_CAST_OK
# define zend_dval_to_lval(d) ((long) (d))
#elif SIZEOF_LONG == 4 && defined(HAVE_ZEND_LONG64)
#elif SIZEOF_LONG == 4
static zend_always_inline long zend_dval_to_lval(double d)
{
if (d > LONG_MAX || d < LONG_MIN) {
return (long)(unsigned long)(zend_long64) d;
double two_pow_32 = pow(2., 32.),
dmod;

dmod = fmod(d, two_pow_32);
if (dmod < 0) {
/* we're going to make this number positive; call ceil()
* to simulate rounding towards 0 of the negative number */
dmod = ceil(dmod) + two_pow_32;
}
return (long)(unsigned long)dmod;
}
return (long) d;
return (long)d;
}
#else
static zend_always_inline long zend_dval_to_lval(double d)
{
/* >= as (double)LONG_MAX is outside signed range */
if (d >= LONG_MAX) {
return (long)(unsigned long) d;
if (d >= LONG_MAX || d < LONG_MIN) {
double two_pow_64 = pow(2., 64.),
dmod;

dmod = fmod(d, two_pow_64);
if (dmod < 0) {
/* no need to call ceil; original double must have had no
* fractional part, hence dmod does not have one either */
dmod += two_pow_64;
}
return (long)(unsigned long)dmod;
}
return (long) d;
return (long)d;
}
#endif
/* }}} */
Expand Down

0 comments on commit 8718755

Please sign in to comment.