diff --git a/hphp/runtime/ext/ext_math.cpp b/hphp/runtime/ext/ext_math.cpp index c656d5adc..74018e30d 100644 --- a/hphp/runtime/ext/ext_math.cpp +++ b/hphp/runtime/ext/ext_math.cpp @@ -95,16 +95,37 @@ Variant f_max(int _argc, CVarRef value, CArrRef _argv /* = null_array */) { return ret; } +/* Logic based on zend_operators.c::convert_scalar_to_number() */ +static DataType zend_convert_scalar_to_number(CVarRef num, + int64_t &ival, + double &dval) { + DataType dt = num.toNumeric(ival, dval, true); + if ((dt == KindOfDouble) || (dt == KindOfInt64)) { + return dt; + } + + if (num.isBoolean() || num.isNull() || + num.isObject() || num.isString()) { + ival = num.toInt64(); + return KindOfInt64; + } + + // Fallback, callers will handle this as an error + ival = 0; + dval = 0.0; + return num.getType(); +} + Variant f_abs(CVarRef number) { int64_t ival; double dval; - DataType k = number.toNumeric(ival, dval, true); + DataType k = zend_convert_scalar_to_number(number, ival, dval); if (k == KindOfDouble) { return fabs(dval); } else if (k == KindOfInt64) { return ival >= 0 ? ival : -ival; } else { - return 0; + return false; } } @@ -112,22 +133,43 @@ bool f_is_finite(double val) { return finite(val);} bool f_is_infinite(double val) { return isinf(val);} bool f_is_nan(double val) { return isnan(val);} -double f_ceil(double value) { return ceil(value);} -double f_floor(double value) { return floor(value);} - -double f_round(CVarRef val, int64_t precision /* = 0 */, - int64_t mode /* = PHP_ROUND_HALF_UP */) { +Variant f_ceil(CVarRef number) { int64_t ival; double dval; - DataType k = val.toNumeric(ival, dval, true); + DataType k = zend_convert_scalar_to_number(number, ival, dval); + if (k == KindOfInt64) { + dval = (double)ival; + } else if (k != KindOfDouble) { + return false; + } + return ceil(dval); +} + +Variant f_floor(CVarRef number) { + int64_t ival; + double dval; + DataType k = zend_convert_scalar_to_number(number, ival, dval); + if (k == KindOfInt64) { + dval = (double)ival; + } else if (k != KindOfDouble) { + return false; + } + return floor(dval); +} + +Variant f_round(CVarRef val, int64_t precision /* = 0 */, + int64_t mode /* = PHP_ROUND_HALF_UP */) { + int64_t ival; + double dval; + DataType k = zend_convert_scalar_to_number(val, ival, dval); if (k == KindOfInt64) { if (precision >= 0) { - return ival; + return (double)ival; } else { dval = ival; } } else if (k != KindOfDouble) { - dval = val.toDouble(); + return false; } dval = php_math_round(dval, precision, mode); return dval; diff --git a/hphp/runtime/ext/ext_math.h b/hphp/runtime/ext/ext_math.h index ac3e7d590..0aca1aae8 100644 --- a/hphp/runtime/ext/ext_math.h +++ b/hphp/runtime/ext/ext_math.h @@ -57,10 +57,10 @@ bool f_is_finite(double val); bool f_is_infinite(double val); bool f_is_nan(double val); -double f_ceil(double value); -double f_floor(double value); -double f_round(CVarRef val, int64_t precision = 0, - int64_t mode = PHP_ROUND_HALF_UP); +Variant f_ceil(CVarRef value); +Variant f_floor(CVarRef value); +Variant f_round(CVarRef val, int64_t precision = 0, + int64_t mode = PHP_ROUND_HALF_UP); double f_deg2rad(double number); double f_rad2deg(double number); diff --git a/hphp/system/idl/math.idl.json b/hphp/system/idl/math.idl.json index ddc8927f5..191e35eb9 100644 --- a/hphp/system/idl/math.idl.json +++ b/hphp/system/idl/math.idl.json @@ -151,13 +151,13 @@ "HasDocComment" ], "return": { - "type": "Double", + "type": "Variant", "desc": "value rounded up to the next highest integer. The return value of ceil() is still of type float as the value range of float is usually bigger than that of integer." }, "args": [ { - "name": "value", - "type": "Double", + "name": "number", + "type": "Variant", "desc": "The value to round" } ] @@ -168,13 +168,13 @@ "HasDocComment" ], "return": { - "type": "Double", + "type": "Variant", "desc": "value rounded to the next lowest integer. The return value of floor() is still of type float because the value range of float is usually bigger than that of integer." }, "args": [ { - "name": "value", - "type": "Double", + "name": "number", + "type": "Variant", "desc": "The numeric value to round" } ] @@ -186,7 +186,7 @@ "HasDocComment" ], "return": { - "type": "Double", + "type": "Variant", "desc": "The rounded value" }, "args": [ @@ -928,4 +928,4 @@ ], "classes": [ ] -} \ No newline at end of file +} diff --git a/hphp/test/zend/bad/ext-standard-math/abs_variation.php b/hphp/test/zend/good/ext-standard-math/abs_variation.php similarity index 100% rename from hphp/test/zend/bad/ext-standard-math/abs_variation.php rename to hphp/test/zend/good/ext-standard-math/abs_variation.php diff --git a/hphp/test/zend/bad/ext-standard-math/abs_variation.php.expectf b/hphp/test/zend/good/ext-standard-math/abs_variation.php.expectf similarity index 100% rename from hphp/test/zend/bad/ext-standard-math/abs_variation.php.expectf rename to hphp/test/zend/good/ext-standard-math/abs_variation.php.expectf