1

当您在 php 中处理浮点数时,您不会想到但需要注意的事情

<?php


    $i = (32.87*100);

    echo $i;                 // outputs 3287
    echo (int) $i;           // outputs 3286 !!
    echo (int) (string) $i   // outputs 3287 

的内部表示$i类似于 3286.9999999。

为什么是$i3287 的字符串表示?

4

2 回答 2

3

让我们看看你的代码:

$i = (32.87*100);

Now$i3287float 略小,如下所示:

echo sprintf('%.30f', $i) . PHP_EOL; //3286.999999999999545252649113535881

但是当你打印(回显)它时,你会得到四舍五入的值。

echo $i;                 // outputs 3287

在这里我们找到了诀窍 - 将 float 转换为 int 意味着简单地切断点之后的部分,尽管它.99999999(...)几乎是 1(但不是!)。所以输出是3286。

echo (int) $i;           // outputs 3286 !!

现在,在最后一个示例中,您首先将 float 转换为字符串,这意味着您已经通过执行所做的操作,echo $i;因为无论您打印什么,PHP 内部都需要转换为字符串。所以它被3286.999999999999545252649113535881转换为"3287",然后被转换为3287,然后被打印。

echo (int) (string) $i   // outputs 3287;

总而言之,float 转换为 string 和 int 的方式是不同的。

编辑关于“四舍五入”的进一步解释

好吧,它并不是真正的四舍五入。我这样说是错误的。

PHP 使用 64 位浮点数(称为double),在十进制表示中具有 14 位精度。

PHP 手册中所述:

浮点数的大小取决于平台,尽管最大约为 1.8e308 且精度约为 14 位十进制数字是常见值(64 位 IEEE 格式)。

这意味着,浮点数可以包含(在大多数情况下)一个 14 位数字(十进制),并且点的放置位置无关紧要。

现在,最重要的是:

转换为字符串不会四舍五入浮点数

例子:

  • $a = 1.23456789012349- 最后一位9是第 15 位,所以你会得到“四舍五入”的浮点数到 1.2345678901235
  • $a = 12345678901234.9- 同上
  • $a = 1.99999999999999- 最后9是第 15 位,所以你会得到2

作为一个字符串,它将完全按照浮点数打印,这意味着 14 位精度。“四舍五入”是在我们在内存中创建浮点变量结构的那一刻。

最后一个例子就是我们在这个主题中讨论的内容。

现在,为什么我犯了那个错误并说“四舍五入”?我误解了 的结果echo sprintf('%.30f', $i)。A 看到更多数字,并认为这是浮点数的实际值。

但事实并非如此。

众所周知,64 位浮点数只有 14 位精度。

那么结果是sprintf从哪里来的呢?

答案其实很简单。

我们已经知道,在二进制系统中并不总是可以表示十进制数。因此,例如一个简单0.1的浮点数(二进制表示)只是一个近似值,因为真正的二进制表示将是无限长的。

现在将二进制系统转换为十进制时,它的工作原理完全相同。可以用二进制表示的内容(这意味着每个浮点值),并不总是可以用十进制表示。

那么什么sprintf('%.30f', $i)是给出将浮点数从二进制转换为十进制的30位精度近似值。

感谢@Quasimodo'sclone 在评论中要求更准确地说明这一点。这让我在这个话题上更深入了一点。

于 2019-01-17T15:59:05.977 回答
0

您将$i(3287) 转换为字符串,然后转换为 int,因此结果保持为 3287。如果您$i转换为 int,您将得到 3286,然后如果您将其转换为字符串,您将得到您想要的.

尝试echo (string) (int) $i

于 2019-01-17T15:53:31.903 回答