我尝试通过 python 和 excel 比较四舍五入后的两个数字的乘法。我使用 openpyxl 库。
轮(4190647.2349499995, 2) -> 4190647.23
但在其他数字中这不起作用!
圆(3335164.9349999996, 2) -> 3335164.93
我在Python中发现了另一种按小数位“循环”的方法
decimal.Decimal(str(number)).quantize(decimal.Decimal(".01"), rounding=decimal.ROUND_HALF_UP)
如何通过Python像Excel中的round函数一样对数字进行四舍五入?
您可以使用
format()
函数对它们进行舍入,如下所示:
float("{:.2f}".format(4190647.2349499995))
>>> 4190647.23
你可以使用这个逻辑,因为 Python 不像 Excel 那样工作
d1 = 3335164.9349999996 # define a Decimal
print(round(round(d1,3),2))
>>3335164.94
您的问题是浮点舍入错误。在实际数学中,18.185 x 230'445.27 = 4,190,647.23495,而不是 4190647.2349499995,145.790 x 22876.5 = 3,335,164.935,而不是 3335164.9349999996。
您会注意到 Excel 已将它们正确舍入为 2dp。
由于二进制算术的怪癖,这些数字在 Python 中被错误表示,导致您看到舍入错误。
我建议您阅读浮点数并使用正确大小的浮点数进行您正在执行的算术运算。
Python 将浮点运算委托给您的硬件:来自 docs:
今天(2000 年 11 月)几乎所有机器都使用 IEEE-754 浮点运算,并且几乎所有平台都将 Python 浮点映射到 IEEE-754“双精度”。 754 个双精度数包含 53 位精度,因此在输入时,计算机会努力将(值)转换为最接近的分数,形式为 J/2**N,其中 J 是恰好包含 53 位的整数。
Excel 可能在幕后使用了一些技巧来纠正(大部分)浮点固有的不精确性。所以简短的回答是:除非你了解 Excel 的内部原理,否则你不可能让 Python 在所有情况下都像 Excel 一样工作。
也就是说,在我链接的文档中,您会找到一些详细的解释,以及一些规避该问题的方法。然后,您可能想尝试一个常见的技巧,如果您知道您的值将具有的最大小数位数:假设该数字是
d
;那么你可以将你的值乘以 10**d
并将它们转换为整数,相乘,然后将乘积除以 10**(d*2)
的商四舍五入到所需的小数位数。一步一步:
d=3
a=int(145.79*10**d) ## 145,790
b=int(22876.5*10**d) ## 22,876,500
round(a*b/10**(d*2),2)
3335164.94
或者,作为一句台词
round(int(145.79*10**d)*int(22876.5*10**d)/10**(d*2),2)
3335164.94
在Excel中,当考虑的舍入位数为5时,round()函数使用银行家的舍入逻辑。如果数字是0-4,则向下舍入,如果是6-9,则向上舍入。如果是 5,则考虑其前一位:如果是偶数 (0,2,4,6,8) 则向下舍入,如果是奇数 (1,3,5,7,9) 则向上舍入。
下面是执行 Excel 样式舍入的函数。它适用于小数点后 6 位。您可以编辑值以提高精度。
def excel_round(x, d):
# Example:
# round(0.105, 2) = 0.10 ; round(0.115, 2) = 0.12
# excel_round(0.105, 2) = 0.11 ; excel_round(0.115, 2) = 0.12
if pd.isnull(x):
return x
val = int(x * math.pow(10,d)) / math.pow(10,d)
rem = (x - val) * math.pow(10,d+1) + 0.0000001
dig = int(rem)
num = val
if dig >= 5.00000:
num = val + float(1/(10 ** d))
return (num)