为什么PHP的sprintf无法可靠地进行5s舍入? [英] Why does PHP's sprintf not round 5s reliably?

查看:237
本文介绍了为什么PHP的sprintf无法可靠地进行5s舍入?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直依赖sprintf('%0.1f', 2.25) === '2.3',但事实证明它来自2.2

I was relying on sprintf('%0.1f', 2.25) === '2.3' but it turns out it comes in at 2.2!

事实上,这似乎是随机的:

In fact it seems random:

php > for ($j=0;$j<=10;$j++) { printf( "%s -> %0.1f\n",$j+ 0.05, $j+0.05); } 
0.05 -> 0.1 // Up, as expected
1.05 -> 1.1 // Up, as expected
2.05 -> 2.0 // Down!
3.05 -> 3.0 // Down!
4.05 -> 4.0 // Down!
5.05 -> 5.0 // Down!
6.05 -> 6.0 // Down!
7.05 -> 7.0 // Down!
8.05 -> 8.1 // Up, as expected
9.05 -> 9.1 // Up, as expected

我完全错了吗?我感觉好像地毯从我身下被拉开了,我在学校学到的所有东西都是错误的……!当然,四舍五入的函数应该始终如一吗? (我注意到round($n, 1)可以正常工作.)

Have I completely missed the point? I feel like a rug is being pulled away from under me and that all I learnt at school is wrong...! Surely a function to round numbers should do it consistently? (I note that round($n, 1) works as expected.)

推荐答案

为解释为什么round比未专门为四舍五入设计的函数提供更好的结果,我们需要考虑双精度浮点数的限制表示.双精度数可以表示15到17个十进制有效数字.摘自关于双精度的维基百科文章:

As an explanation of why round can offer better results than a function not specifically designed for rounding, we need to consider the limits of the double precision floating point representation. Doubles can represent between 15 and 17 decimal significand digits. From the Wikipedia article on double precision:

如果将具有最多15个有效数字的十进制字符串转换为IEEE 754双精度表示形式,然后再转换回具有相同有效数字数量的字符串,则最终字符串应与原始字符串匹配.如果将IEEE 754的双精度转换为具有至少17个有效数字的十进制字符串,然后再转换回双精度,则最终数字必须与原始数字匹配.

If a decimal string with at most 15 significant digits is converted to IEEE 754 double precision representation and then converted back to a string with the same number of significant digits, then the final string should match the original. If an IEEE 754 double precision is converted to a decimal string with at least 17 significant digits and then converted back to double, then the final number must match the original

在大多数情况下,round的实现可以并且应该利用它来做正确的事".

The implementation of round can and should make use of this to "do the right thing" in most cases.

示例1:

<?=number_format(2.05,14); //give me 15 significant digits. Guaranteed to produce the orginal number

输出:

2.05000000000000

示例2:

<?=number_format(2.05,16); //give me 17 significant digits. Not guaranteed to produce the orginal number

输出:

2.0499999999999998

这只是IEEE 754行为的演示.

This is just a demonstration the IEEE 754 behavior.

我将猜测(因为我尚未阅读其实现),sprintf并没有真正尝试对舍入进行任何特别智能的操作,而round可能会尝试正确"舍入(每个有关您要求的有效位数的信息.

I am going to guess (because I haven't read its implementation) that sprintf doesn't really try to do anything particularly intelligent with regards to rounding, whereas round probably tries to round "correctly" (per IEEE 754) with respect to the number of significant digits you asked for.

这篇关于为什么PHP的sprintf无法可靠地进行5s舍入?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆