谁能解释为什么 NAN
和等于 NAN
的变量的行为因 PHP 版本而异?
考虑以下代码:
$nan = NAN;
print "PHP Version: " . phpversion(). "\n" .
'0 < NAN ? ' . ( 0 < NAN ? 'TRUE' : 'FALSE' ) . "\n" .
'0 > NAN ? ' . ( 0 > NAN ? 'TRUE' : 'FALSE' ) . "\n" .
'0 == NAN ? ' . ( 0 == NAN ? 'TRUE' : 'FALSE' ) . "\n" .
'0 < $nan ? ' . ( 0 < $nan ? 'TRUE' : 'FALSE' ) . "\n" .
'0 > $nan ? ' . ( 0 > $nan ? 'TRUE' : 'FALSE' ) . "\n" .
'0 == $nan ? ' . ( 0 == $nan ? 'TRUE' : 'FALSE' ) . "\n" .
'is_nan(NAN) ' . ( is_nan(NAN) ? 'TRUE' : 'FALSE' ) . "\n" .
'is_nan($nan) ' . ( is_nan($nan) ? 'TRUE' : 'FALSE' ) . "\n" .
'gettype(NAN) is ' . gettype(NAN) . "\n" .
'gettype($nan) is ' . gettype($nan) . "\n";
现在,如果我针对多个版本的 PHP(使用 MAMP)运行此代码,结果如下:
PHP Version: 5.3.5
0 < NAN ? TRUE
0 > NAN ? TRUE
0 == NAN ? FALSE
0 < $nan ? TRUE
0 > $nan ? TRUE
0 == $nan ? FALSE
is_nan(NAN) TRUE
is_nan($nan) TRUE
gettype(NAN) is double
gettype($nan) is double
PHP Version: 5.6.30 (and 5.5.30, 5.4.45)
0 < NAN ? FALSE
0 > NAN ? FALSE
0 == NAN ? FALSE
0 < $nan ? FALSE
0 > $nan ? FALSE
0 == $nan ? FALSE
is_nan(NAN) TRUE
is_nan($nan) TRUE
gettype(NAN) is double
gettype($nan) is double
PHP Version: 7.1.1 (and 7.0.15)
0 < NAN ? TRUE
0 > NAN ? TRUE
0 == NAN ? FALSE
0 < $nan ? FALSE
0 > $nan ? FALSE
0 == $nan ? FALSE
is_nan(NAN) TRUE
is_nan($nan) TRUE
gettype(NAN) is double
gettype($nan) is double
PHP 中的函数是否可以依赖于与 NAN 的比较,或者 NAN 是否应该仅与 is_nan()
一起使用?
最佳答案
This bug has now been fixed by this commit. The explanation bellow shows what was causing it.
关于你的第一个问题,似乎从 PHP7 开始你会得到不同的结果,这取决于表达式是在编译期间还是在运行时求值。
首先,重要的是要注意,根据 IEEE754,所有比较中其中一个元素是 NAN
。 , 应该返回 false
.您可以在 this answer 中找到一些详细信息.考虑到这一点,5.6 的行为似乎是正确的。
因此,对于运行时评估(0 < $nan
),该比较由 this code 在 VM 中完成:
result = ((double)Z_LVAL_P(op1) < Z_DVAL_P(op2));
该操作会将 0 分配给 result
最终返回。这将为我们提供 FALSE
的预期输出.
在编译时评估(0 < NAN
)的情况下,比较由this code在编译期间完成:
case TYPE_PAIR(IS_LONG, IS_DOUBLE):
Z_DVAL_P(result) = (double)Z_LVAL_P(op1) - Z_DVAL_P(op2);
ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
return SUCCESS;
这里还有一些其他的事情发生,减法的结果0 - NAN = NAN
该值然后通过 ZEND_NORMALIZE_BOOL
宏内容如下:
#define ZEND_NORMALIZE_BOOL(n) \
((n) ? (((n)>0) ? 1 : -1) : 0)
如您所见,如果(n) > 0
是false
(这是 NAN
的情况),宏将返回 -1
.
然后将该值传递给 is_smaller_function
其中 you'll find :
ZVAL_BOOL(result, (Z_LVAL_P(result) < 0));
鉴于此时result
持有 -1
, 这将被评估为 TRUE
.
关于你的第二个问题,我建议你永远不要依赖与 NAN
的比较。并坚持使用 is_nan()
.请注意,即使是 NAN == NAN
评估为 false
.
关于php - 在 PHP 版本中正确处理 NAN,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45247996/