diff options
Diffstat (limited to 'Zend/zend_operators.h')
-rw-r--r-- | Zend/zend_operators.h | 30 |
1 files changed, 24 insertions, 6 deletions
diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index 93c60e490..a82c14b8c 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -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 /* }}} */ |