PHP中sprintf(‘%.2f‘, $str)精度问题?

文章探讨了PHP中sprintf函数的%.2f格式化问题,揭示了并非标准的四舍五入,而是遵循特定规则:非5进位,5前奇数进,5后有非0则进。解释了浮点数精度导致的看似四舍五入实则不同结果的现象。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考:php中sprintf('%.2f', $str)的一个让人无法理解的问题?

首先看一段代码示例

echo sprintf('%.2f',123.455); 
// 123.45

echo sprintf('%.2f',12.455); 
// 12.46

PHP 的 sprintf('%.2f', $str) 通常被认为是四舍五入,应该都是输出 0.46 才对;但是两个结果不同,一个 0.46 一个 0.45,为什么呢?

sprintf('%.2f', $str) 的“四舍五入”问题

在 PHP 中 sprintf 经常被用来格式化数据,当 sprintf 用 %.*f 格式化时经常被认为是“四舍五入”,但实事上并不是数学上的“四舍五入”,而是“四舍六入五成双”。

(1)当保留精度的下一位非 5 时,按正常的四舍五入;

(2)当保留精度的下一位是 5 时,5 的前一位是奇数则进位,是偶数则舍弃;

(3)若 5 的后面还有非 0 的部分,则无论 5 的前一位是奇数还是偶数,都进行进位;

1.当保留精度的下一位不是 5 时,按正常的四舍五入;

echo sprintf('%.2f', 12.464);
// out 12.46

echo sprintf('%.2f', 12.466);
// out 12.47

2.当保留精度的下一位是 5 时,5 的前一位是奇数则进位,是偶数则舍弃;

echo sprintf('%.2f', 12.465);
// out 12.46

echo sprintf('%.2f', 12.455);
// out 12.46

3.若 5 的后面还有非 0 的部分,则无论 5 的前一位是奇数还是偶数,都进行进位;

echo sprintf('%.2f', 12.4651);
// out 12.47

解释最初的示例代码

十进制浮点数在计算机内部也是用二进制表示的,有限位置的 十进制浮点数 转换成二进制很有可能是无限循环的数。如:

// 123.455
1111011.01110100011110101110000101...101  

将 123.455 转换成二进制就会发现 00011110101110000101 是循环的,计算机不可能保存一个无限长的数字,双精度浮点数 下使用 64 位(8字节)来存储一个浮点数,其中小数位有 53 位。53 位之后的被舍去了,这样就变成有限位,但是也带来了精度问题。

echo printf('%.53f',123.455);
// 123.45499999999999829469743417575955390930175781250000000

​echo printf('%.53f',12.455);
// 12.45500000000000007105427357601001858711242675781250000

将全部 53 位小数显示出来你会发现,123.455 其实是 123.454999.... 第三位其实是 4 并不是 5,所以直接被舍去了。这个是浮点数精度问题,同样存在于其他语言中。 

echo sprintf('%.2f',123.455); 
// 123.45

echo sprintf('%.2f',12.455); 
// 12.46

在 PHP 中可以使用 round 方法来进行 四舍五入

echo round(123.455, 2);
// 123.46

echo round(12.455, 2);
// 12.46
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值