summaryrefslogtreecommitdiff
path: root/Zend/zend_operators.h
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_operators.h')
-rw-r--r--Zend/zend_operators.h30
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
/* }}} */