Skip to main content
 首页 » 编程设计

python之格式化数值与舍入值之间的差异

2025年05月04日14shihaiming

我使用 python 和 numpy 发现了这种奇怪的行为:

print('%10.3f' %0.4975) 

返回 0.497,而

numpy.round(0.4975,3) 

按预期返回 0.498。 对于其他类似的数字,我总是得到打印语句来提供正确舍入的值(例如:0.5975 --> 0.598)。 为什么是这样? 我在 Windows 7 上使用 python 3.4 和 numpy 1.9.2。

请您参考如下方法:

在 double 中,0.4975 是 8962163258467287/18014398509481984,比实数 0.4975 略小于。因此,Python 的 round 函数将其四舍五入为 0.497。

相比之下,0.5975 变为 5381801554707743/9007199254740992,比实数 0.5975 略更多。所以我们在四舍五入时得到了预期的 0.598。

为什么 NumPy 将 0.4975 舍入为 0.498?它的算法有点不同:要舍入到 N 位,它将给定数字乘以 10 的 N 次方,舍入到最接近的整数(最好是偶数),然后除以 10^N。在乘以10的幂的过程中,截断的方向发生变化;结果通常会得到一个半整数。 (示例:0.15*10 = 1.5 正好是 3/2,尽管 0.15 不正好是 3/20)。

简单来说,np.round(x, 3) 等同于round(x*1000)/1000。您可以检查当应用于 x = 0.4975 时两者都返回 0.498。实际上,在 double 中,0.4975*1000 恰好 497.5(即 995/2),然后正确选择舍入方向。

以下是 0.05、0.15、0.25 等四舍五入方式的比较:

python

>>> [round((2*i+1)/20, 1) for i in range(10)]  
[0.1, 0.1, 0.2, 0.3, 0.5, 0.6, 0.7, 0.8, 0.8, 0.9]   

NumPy

>>> import numpy as np 
>>> np.around([(2*i+1)/20 for i in range(10)], 1) 
array([ 0. ,  0.2,  0.2,  0.4,  0.4,  0.6,  0.6,  0.8,  0.8,  1. ]) 

这里的 NumPy 输出是人们在不考虑二进制表示的情况下所期望的。

然而,np.around([(2*i+1)/200 for i in range(100)], 2) 表明 NumPy 的算法并不总是符合预期,或者:有两个数字(0.55 和 0.57),末尾是奇数。问题是,例如,0.545*100 并不完全是 109/2;相反,它是 7670193115365377/140737488355328。