【发布时间】:2020-11-13 11:21:06
【问题描述】:
在 StackOverflow 和其他地方已经提出了许多关于 Python 使用浮点数的计算令人困惑的行为的问题 - 通常返回的结果显然有少量错误。 explanation for this 总是链接到。但是,通常不会提供实用的简单解决方案。
这不仅仅是错误(通常可以忽略不计) - 它更多的是获得像 3.999999999999999 这样的结果来获得像 8.7 - 4.7 这样的简单总和的混乱和不雅。
我已经为此编写了一个简单的解决方案,我的问题是,为什么 Python 不会在后台自动实现这样的事情?
基本概念是将所有浮点数转换为整数,进行运算,然后适当地转换回浮点数。上述链接文档中解释的困难仅适用于浮点数,而不适用于整数,这就是它起作用的原因。代码如下:
def justwork(x,operator,y):
numx = numy = 0
if "." in str(x):
numx = len(str(x)) - str(x).find(".") -1
if "." in str(y):
numy = len(str(y)) - str(y).find(".") -1
num = max(numx,numy)
factor = 10 ** num
newx = x * factor
newy = y * factor
if operator == "%":
ans1 = x % y
ans = (newx % newy) / factor
elif operator == "*":
ans1 = x * y
ans = (newx * newy) / (factor**2)
elif operator == "-":
ans1 = x - y
ans = (newx - newy) / factor
elif operator == "+":
ans1 = x + y
ans = (newx + newy) / factor
elif operator == "/":
ans1 = x / y
ans = (newx / newy)
elif operator == "//":
ans1 = x // y
ans = (newx // newy)
return (ans, ans1)
这无疑是相当不优雅的,可能需要稍加思考来改进,但它可以完成工作。该函数返回一个具有正确结果(通过转换为整数)和不正确结果(自动提供)的元组。以下是如何提供准确结果的示例,而不是正常执行。
#code #returns tuple with (correct, incorrect) result
print(justwork(0.7,"%",0.1)) #(0.0, 0.09999999999999992)
print(justwork(0.7,"*",0.1)) #(0.07, 0.06999999999999999)
print(justwork(0.7,"-",0.2)) #(0.5, 0.49999999999999994)
print(justwork(0.7,"+",0.1)) #(0.8, 0.7999999999999999)
print(justwork(0.7,"/",0.1)) #(7.0, 6.999999999999999)
print(justwork(0.7,"//",0.1)) #(7.0, 6.0)
TLDR:本质上的问题是,为什么浮点数可以存储为以 2 为底的二进制分数(本质上是不精确的),而它们可以以与整数相同的方式存储(可以工作)?
【问题讨论】:
-
这只能在一个简单的域中“工作”,特别是带有短十进制数字的简单算术。当涉及更复杂的计算时,它将不起作用,例如产生无法用短十进制数字表示的结果的非小数分数或计算链。至于为什么使用浮点而不是固定的整数格式,这是因为点是浮动的:浮点数具有内置的比例,使其能够处理非常大或非常小的数字,例如物理学中发生的那样.这称为动态范围。
-
Decimal floating point 是一个东西。不过,在大多数系统上,您可以更好地支持二进制浮点(这更容易在硬件中有效实现)。
-
主要原因是性能。对于进行数十亿次浮点计算的程序来说,这是一笔太大的开销。而且绝对不仅仅是 Python。
-
看起来 python 有一个用于十进制浮点数的模块:docs.python.org/3/library/decimal.html
-
如果我将其更改为
return ans(您声称的“正确”结果),那么justwork(justwork(1, '/', 3), '*', 3)将导致0.9999999999999998。而使用return ans1(您声称的“不正确”结果)会导致1.0。
标签: python floating-point binary floating-accuracy ieee-754