有人可以解释为什么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()
一起使用?
答案 0 :(得分:3)
此错误现已由this commit修复。下面的解释说明了导致它的原因。
关于你的第一个问题,似乎从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
。
答案 1 :(得分:1)
这是documentation关于NaN
所说的内容:
<强>的NaN 强>
某些数值运算可能会产生由常量
NAN
表示的值。此结果表示浮点计算中未定义或不可表示的值。除了TRUE
之外,对此值与任何其他值(包括其自身)进行任何宽松或严格的比较,都会得到FALSE
的结果。由于
NAN
表示任意数量的不同值,因此NAN
不应与其他值(包括其自身)进行比较,而应使用is_nan()
进行检查。
简单来说,NaN
不是一个值。它是一种表示法,表示使用浮点标准使用实数的内部表示无法计算或存储的结果。
NaN
不等于其他任何东西。 NaN
即使与另一个NaN
不相等,因为许多不同的计算都可以产生NaN
。
检查结果是NaN
的唯一可靠方法是使用is_nan()
函数。
只有代码中的最后四个测试有效:
is_nan(NAN) TRUE
is_nan($nan) TRUE
gettype(NAN) is double
gettype($nan) is double