让我们看看你的代码:
$i = (32.87*100);
Now$i
比3287
float 略小,如下所示:
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 在评论中要求更准确地说明这一点。这让我在这个话题上更深入了一点。