php - 在 PHP 版本中正确处理 NAN

标签 php nan

谁能解释为什么 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) > 0false (这是 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/

相关文章:

php - 使用 php 为单个页面选择独特的样式表

php - 如何在 Laravel 5.5 中对表格进行分页?

javascript - 在 Javascript 中,添加数组时如何避免 NaN

Python 数据帧 : Why does my values change to NaN if I change the indices?

php - 当 PHP Gearman 客户端无法连接到服务器时,我得到与无法获取新作业时相同的代码

PHP 在具有多个表单输入的同一列中添加数据

php - 如果mysql表中user_id不存在,如何插入新数据

python - 属性错误 : 'float' object has no attribute 'split'

python - numpy 数组 : replace nan values with average of columns

python - Pandas ffill 限制组 nan 仅小于限制