让我们看看你的代码:
$i = (32.87*100);
现在$i 比3287 略小,如下所示:
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 manual中所述:
float 的大小取决于平台,尽管最大约为 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 in float(二进制表示)只是一个近似值,因为真正的二进制表示将无限长。
现在将二进制系统转换为十进制时,它的工作原理完全相同。可以用二进制表示的东西(这意味着每个浮点值),并不总是可以用十进制表示。
那么sprintf('%.30f', $i) 是给出将浮点数从二进制转换为十进制的 30 位精度近似值。
感谢@Quasimodo'sclone 在评论中要求更准确地说明这一点。这让我对这个话题有了更深入的了解。