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

问题描述 投票:0回答:2

我注意到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.2
具有与
float(Decimal('0.1') + Decimal('0.2'))
相同的结果? 它也应该应用于其他数学运算,如
**
和相等比较,如
==

python math decimal precision
2个回答
0
投票

一种方法是创建一个名为

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
投票

IPythonhooks 用于在执行前遍历代码的 AST,因此您可以访问任何浮点数,并将其转换为十进制(也转换整数,因此 1/3 将是十进制):

import ast
from decimal import Decimal

class ReplaceFloatWithDecimal(ast.NodeTransformer):
    def visit_Constant(self, node):
        if isinstance(node.n, (float, int)):
            return ast.Call(func=ast.Name(id='Decimal', ctx=ast.Load()),
                            args=[ast.Call(func=ast.Name(id='str', ctx=ast.Load()),
                                           args=[node], keywords=[])],
                            keywords=[])
        return self.generic_visit(node)

get_ipython().ast_transformers.append(ReplaceFloatWithDecimal())

(在 IPython shell 中执行)

为了使解决方案完整,您可能需要打印没有冗余的数字

Decimal('...')
:

def decimal_formatter(s, printer, cycle):
    printer.text(str(s))
get_ipython().display_formatter.formatters['text/plain'].for_type(Decimal, decimal_formatter)

现在你有:

In [2]: 0.1 + 0.2
Out[2]: 0.3

附注这些使用 python 作为计算器的调整(以及更多)在我的包calcpy中使用。

© www.soinside.com 2019 - 2024. All rights reserved.