解释器和脚本中的 Python 精确数学计算,无需一直键入十进制模块

Python precision math calculation in interpreter and script without typing decimal module all the time

提问人:ONLYA 提问时间:3/4/2023 更新时间:3/4/2023 访问量:123

问:

我注意到 python 中的数学运算不像以前那么精确,尤其是涉及浮点数的运算。我知道这是由于二进制数表示的性质,我们可以通过执行以下操作来解决这个问题:

from decimal import Decimal
a = Decimal('0.1') + Decimal('0.2')

我甚至可以做一些进一步的事情,比如:

def func(a, b, operator):
    a_ = Decimal('{}'.format(a))
    b_ = Decimal('{}'.format(b))
    return eval('float(a_ {} b_)'.format(operator))

func(0.1, 0.2, '+') # will return 0.3

但是,我不想走到这一步。事实上,我一直在使用 python 作为计算器或 Matlab 替代品。为了快速计算而必须编写更多的东西并不方便。decimal 模块的上下文设置还要求在数字前面写上“Decimal”。

这个 5 年前的问题集中在脚本上,而不是在口译员内部工作。我也尝试了代码示例,但它没有按预期工作。

有没有一种快速而肮脏的方法可以使python执行具有相同的结果? 它也应该应用于其他数学运算,如等式比较。0.1 + 0.2float(Decimal('0.1') + Decimal('0.2'))**==

Python 数学 十进制 精度

评论

1赞 Mark Dickinson 3/4/2023
“不像以前那么精确”是什么意思?在什么时候之前?Python 浮点运算的基本原理几十年来一直没有改变。
1赞 jodag 3/4/2023
Matlab 和 Python 为 生成相同的值。两者都完全产生.Matlab 隐藏了额外的小数,但会显示完整值。这是几乎所有现代语言使用的固定浮点精度的限制。您看到的是打印精度的差异,而不是内存中实际值的差异。0.1+0.20.3000000000000000444089209850062616169452667236328125fprintf('%.52f',0.1+0.2)
0赞 ONLYA 3/4/2023
@MarkDickinson我相信它可能就像 jodag 所说的那样:以前的版本可能会通过消除额外的小数来隐藏实际结果。我忘记了版本,但它在特定版本之后返回了真正的小数。也许我的记忆中有什么不对劲。
0赞 ONLYA 3/4/2023
@MarkDickinson我相信这个问题不是重复的,因为在我看来,提供的答案仅适用于脚本。浮点数未作为字符串文本倒回 Decimal 构造函数。

答:

0赞 Alan 3/4/2023 #1

一种方法是创建一个名为 (for decimal) 的新对象类型。D

from decimal import Decimal

class D:
  def __init__(self, d: float | int):
    self.d = Decimal(str(d))

  def __add__(self, other_d: D):
    return self.d + other_d.d

通过覆盖 上的方法,可以重新创建所需的加法行为。同样,您可以覆盖与每个算术运算符对应的魔术方法。(例如,覆盖 等)__add__D__eq__==

一旦到位,你可以做一些事情,比如:

a = D(0.1)
b = D(0.3)
c = a + b

print(c)
-> 0.4 (Decimal type)

评论

0赞 Alan 3/4/2023
请注意,参数(例如 、 和 )的键入取决于 python 版本。如果它们出现错误,只需将其删除即可。d: float | intother_d: D
0赞 jodag 3/4/2023
这似乎并不比仅仅使用D=Decimal
0赞 ONLYA 3/4/2023
在新类中使用内部方法是一个很好的方法。但是,有没有办法将 python 将浮点文字解释为 Decimal 类字符串输入的方式?结果,在做了一系列事情之后,我就可以输入,这将返回0.3?0.1+0.2
0赞 Alan 3/4/2023
@ONLYA这是一个有趣的问题,这里回答了一个相关的问题:stackoverflow.com/a/7880276/12705481。要点归结为抽象语法树;这些是将编写的 Python 代码存储为编译器指令序列的数据结构。您可以通过标准库模块与它们进行交互。也许有一种方法可以做你想做的事情,尽管如果有的话,它是非常基本和棘手的事情(当然超出了我的理解!我的解决方案至少提供了一个速记。ast
0赞 Alan 3/4/2023
@jodag优点是字符串转换。如果这样做,则会出现舍入错误。因此,您必须避免舍入错误。这个解决方案让我们更接近于使用“原始”浮点数。Decimal(0.1)Decimal("0.1")