草庐IT

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

coder 2024-04-15 原文

谁能解释为什么 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 版本中正确处理 NAN的更多相关文章

  1. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  2. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

  3. ruby - Infinity 和 NaN 的类型是什么? - 2

    我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

  4. ruby-on-rails - 在 ruby​​ .gemspec 文件中,如何指定依赖项的多个版本? - 2

    我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这

  5. ruby-on-rails - 如果我将 ruby​​ 版本 2.5.1 与 rails 版本 2.3.18 一起使用会怎样? - 2

    如果我使用ruby​​版本2.5.1和Rails版本2.3.18会怎样?我有基于rails2.3.18和ruby​​1.9.2p320构建的rails应用程序,我只想升级ruby的版本,而不是rails,这可能吗?我必须面对哪些挑战? 最佳答案 GitHub维护apublicfork它有针对旧Rails版本的分支,有各种变化,它们一直在运行。有一段时间,他们在较新的Ruby版本上运行较旧的Rails版本,而不是最初支持的版本,因此您可能会发现一些关于需要向后移植的有用提示。不过,他们现在已经有几年没有使用2.3了,所以充其量只能让更

  6. ruby-on-rails - 获取 inf-ruby 以使用 ruby​​ 版本管理器 (rvm) - 2

    我安装了ruby​​版本管理器,并将RVM安装的ruby​​实现设置为默认值,这样'哪个ruby'显示'~/.rvm/ruby-1.8.6-p383/bin/ruby'但是当我在emacs中打开inf-ruby缓冲区时,它使用安装在/usr/bin中的ruby​​。有没有办法让emacs像shell一样尊重ruby​​的路径?谢谢! 最佳答案 我创建了一个emacs扩展来将rvm集成到emacs中。如果您有兴趣,可以在这里获取:http://github.com/senny/rvm.el

  7. ruby-on-rails - 如何在发布新的 Ruby 或 Rails 版本时收到通知? - 2

    有人知道在发布新版本的Ruby和Rails时收到电子邮件的方法吗?他们有邮件列表,RubyonRails有一个推特,但我不想听到那些随之而来的喧嚣,我只想知道什么时候发布新版本,尤其是那些有安全修复的版本。 最佳答案 从therailsblog获取提要.http://weblog.rubyonrails.org/feed/atom.xml 关于ruby-on-rails-如何在发布新的Ruby或Rails版本时收到通知?,我们在StackOverflow上找到一个类似的问题:

  8. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  9. Ruby-vips 图像处理库。有什么好的使用示例吗? - 2

    我对图像处理完全陌生。我对JPEG内部是什么以及它是如何工作一无所知。我想知道,是否可以在某处找到执行以下简单操作的ruby​​代码:打开jpeg文件。遍历每个像素并将其颜色设置为fx绿色。将结果写入另一个文件。我对如何使用ruby​​-vips库实现这一点特别感兴趣https://github.com/ender672/ruby-vips我的目标-学习如何使用ruby​​-vips执行基本的图像处理操作(Gamma校正、亮度、色调……)任何指向比“helloworld”更复杂的工作示例的链接——比如ruby​​-vips的github页面上的链接,我们将不胜感激!如果有ruby​​-

  10. ruby-on-rails - 安装多个版本的 Rails 会覆盖以前的安装吗? - 2

    如果我一直输入geminstallrails使用不同版本的Rails会怎样?例如,我可以输入:geminstallrails--verson3.2.10或geminstallrails这给了我版本3.2.12。问题每次安装都会覆盖之前的吗?它会删除所有旧文件并添加我正在安装的新版本吗?或者如果我运行它两次,它会保留一些文件吗?我正在使用Ubuntu。 最佳答案 它将安装两个独立的gem。实际的可执行文件rails将调用最新版本。你可以覆盖它__例如,rails_3.2.10_将执行Rails3.2.10。bundler顺便说一下,如

随机推荐