-2

我想使用以下代码将 python 中的数字四舍五入到小数点后 2 位:

a = 3260
b = 0.000075
c =  a * b # // (0.24449999999999997)
result = round(a * b, 2)

但我得到的结果是:0.23999999999999999

我将此与 excel VBA 进行result比较0.24

我不知道为什么(a)这个数字没有被截断,(b)为什么它与 VBA 等价物不同:

WorksheetFunction.MRound(c, 0.01)

任何提示表示赞赏!

编辑:我正在为 VS2010 和 python 2.6 使用 python 工具。

4

1 回答 1

2

值 0.24 不能精确地表示为 IEEE 二进制浮点数。这就是您获得 0.23999999999999999 的原因。我不是 100% 确定 VBA 是否使用相同的格式。如果确实如此,则可能是“意识到” 0.23999999999999999 太接近 0.24 并显示后者。但仅在显示时。在内部,仍会存储不精确的数字,因为此 IEEE 格式中不存在精确值 0.24。

您可以通过显示带有 2 位小数的结果来强制执行类似于 VBA 的行为。格式化例程在这个意义上做得更好,因为它们四舍五入到字符串表示,这当然支持“2.40”(作为字符串,而不是数字)。

print( "%.2f" % 0.23999999999999999 )

另一种解决方案是使用十进制浮点或定点算术包,能够以完美的精度表示十进制数(但不是二进制数)。Python 的标准包decimal做得非常好,并且支持两者。

第三种解决方案是以某种方式以简单且个人化但非常费力的方式实现这样的包。假设您所有的数字都需要以 2 位小数存储,您可以将它们缩放 100 并将它们存储为整数。例子:

a =  1326048  # /100=  13260.48 ; s=2
b =   234493  # /100=   2344.93 ; s=2
c = 34756334  # /100= 347563.34 ; s=2
# All three numbers are in the same scale, so they can be added directly.  Scale of the result is the same as the numbers (s=2)
d = a + b + c  # /100; s=2
# In multiplication, scale of the result is the sum of the scale of the factors. 
# This has the advantage that the scale of operands can be different.
e = a * b  # /10000; s=4
# But we want to go back to 2 decimals quickly.  So, round to 2 decimals.  And yes, division subtracts scales.
e = ( e + 50 ) // 100  # /100 s=2

我根本不会推荐这个(或下一个“解决方案”)。他们在这里只是为了最低限度地解释这种包是如何工作的。

您还可以在单​​独的变量中跟踪比例并在运行时计算必要的比例调整,但这完全等同于自己构建上述软件包之一。在您的特定情况下,

a_m= 326
a_s= -1   # a= a_m / 10**a_s = 326 / 10**-1 = 3260
b_m= 75
b_s= 6    # b= b_m / 10**b_s = 75 / 10**6 = 0.000075
c_m= a_m * b_m  # =24450
c_s= a_s + b_s  # = -1 + 6 = 5  ;  c= c_m / 10**c_s = 24450 / 10**5 = 0.24450
# Round to 2 decimals
r= 2
d_m= ( c_m + 10**(c_s-r)//2 ) // 10**(c_s-r)
# d_m = ( 24450 + 10**(5-2)//2 ) // 10**(5-2) = ( 24450 + 500 ) // 1000 = 24
d_s= r  # = 2  ;  d= dm / 10**ds = 24 / 10**2 24 / 100 = 0.24

此时,您要输出“未缩放”版本的c. 两种选择是:

print( ("%d.%0"+str(c_s)+"d") % ( c // 100 , c % 100 ) )  # Which is the same as...
print( ("%d.%02d") % ( c // 100 , c % 100 ) )  # The case c_s < 0 requires a different expression

或采用浮点方式

print( "%.2f" % c / 100 )
于 2013-08-15T06:07:12.787 回答