【问题标题】:Why two float variables with PHP_INT_MAX values are same unless one of them is added with value greater than 1025为什么两个具有 PHP_INT_MAX 值的浮点变量是相同的,除非其中一个变量的值大于 1025
【发布时间】:2015-08-02 10:57:19
【问题描述】:
<?php
$x=PHP_INT_MAX;
echo ((float)($x+1026)==(float)($x))?'EQUAL':'Not Equal';

我知道浮点运算不精确,$x 和 $x+1 非常接近,以至于它们被舍入到相同的浮点值,如果你使用 1 到 1025 之间的任何数字,它会显示输出为 EQUAL 但是只有在您使用超过 1025 的值后,它才会开始输出“不等于”。我想知道为什么?背后的原因是什么?为什么只在 1025 之后?

【问题讨论】:

  • 您需要开始查看bit-level representation of floats,这也取决于您运行的是 32 位还是 64 位 PHP
  • 你有哪个 PHP 版本?例如,在我的测试中,“不等于”与“$x + 10”
  • 看看this convertor,它可以让你看到不同数字的浮点表示
  • @mmm: 我的 PHP 版本是 5.5.24 它的 Mac OS X 64 位,我不认为浮动响应依赖于 php 版本,它是别的东西。
  • 仅仅因为您使用的是 64 位操作系统,并不意味着您正在运行 64 位 PHP。您可以使用PHP_INT_SIZE or PHP_INT_MAX constants 进行检查 - 在 32 位 PHP 上,PHP_INT_MAX 为 2147483647;在 64 位上,它是 9223372036854775807;而 PHP_INT_SIZE 在 32 位 PHP 上为 4,在 64 位 PHP 上为 8

标签: php floating-point floating-accuracy floating-point-precision


【解决方案1】:

使用 float,您的假设 $x == $x + 1 不一定正确:

$x=2;
echo ((float)($x+1)==(float)($x))?'EQUAL':'Not Equal';

产生“不相等”。

在 cmets (http://www.h-schmidt.net/FloatConverter/IEEE754.html) 中链接的转换器中,您可以重现此内容。十进制2.0 产生0x40000000,十进制3.0 产生0x40400000,因此它们在IEEE754 浮点表示方面确实有所不同。

而,例如,十进制 0.1 不能表示为浮点数:0x3dcccccd,即 0.10000000149011612

什么是小数 9223372036854775807?那是0x5f000000,即9.223372E18,即9223372180000000000

什么是小数 9223372036854775808 (PHP_MAX_INT + 1)?那也是0x5f000000

什么是小数 9223372036854776832 (PHP_MAX_INT + 1025)?那也是0x5f000000

什么是小数 9223372036854776833 (PHP_MAX_INT + 1026)?那也是0x5f000000

它们都是一样的。

而,例如:十进制 9223373000000000000 (PHP_MAX_INT + 963145224193)?那是0x5f000001,即9.223373E18,即9223373000000000000

现在,为什么会这样:

((float)($x+1025)==(float)($x+1026))?'EQUAL':'Not Equal';

产生“不等于”?

您正在向PHP_MAX_INT 添加一个整数。

$x=PHP_INT_MAX;
$y=PHP_INT_MAX-1;
$z=PHP_INT_MAX+1;
var_dump($x);
var_dump($y);
var_dump($z);

产量:

int(9223372036854775807)
int(9223372036854775806)
float(9.2233720368548E+18)

PHP 隐式转换太大而无法浮动的整数。这就是您基本上迷失在 PHP 内部的地方(至少在我看来),因为从这里开始,您将永远不知道会发生什么(尽管不了解 PHP 内部,请随时纠正我)。

注意这一点:

$x=PHP_INT_MAX;
$a=(float)($x+1025.0); // 1025 float
$b=(float)($x+1026.0); // 1026 float
$c=(float)($x+1025); // 1025 int
$d=(float)($x+1026); // 1026 int
var_dump($x);
var_dump($a);
var_dump($b);
var_dump($c);
var_dump($d);
var_dump($a==$b);
var_dump($a===$b);
var_dump($c==$d);
var_dump($c===$d);

产量:

int(9223372036854775807)
float(9.2233720368548E+18)
float(9.2233720368548E+18)
float(9.2233720368548E+18)
float(9.2233720368548E+18)
bool(true)
bool(true)
bool(false)
bool(false)

如果你在PHP_MAX_INT 上加上一个整数($x+1026),它就会被转换为浮点数,当你加上一个浮点数($x+1026.0)时,它当然也是浮点数。但是,显然,它们在内部并不相同,请参见上面的比较。

底线:

  • 不要比较浮点数是否相等
  • 小心你的演员阵容; (float)($x+1026) 是一个整数加法,然后转换为浮点数,而(float)($x+1026.0)$x 转换为浮点数,然后添加浮点数1026.0,然后(多余地)转换为浮点数。

编辑:另外,请参阅:

【讨论】:

    猜你喜欢
    • 2013-09-10
    • 2018-07-05
    • 1970-01-01
    • 2021-03-22
    • 1970-01-01
    • 1970-01-01
    • 2017-01-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多