当前位置: 首页 > 面试题库 >

澄清Python中的小数类型

应瀚
2023-03-14
问题内容

每个人都知道,或者至少每个程序员都应该知道,使用该float类型可能会导致精度错误。但是,在某些情况下,精确的解决方案将是不错的选择,并且在某些情况下,使用epsilon值进行比较是不够的。无论如何,这不是重点。

我知道DecimalPython中的类型,但从未尝试使用它。它指出“十进制数可以精确表示”,我认为这意味着可以实现任何实数的聪明实现。我的第一次尝试是:

>>> from decimal import Decimal
>>> d = Decimal(1) / Decimal(3)
>>> d3 = d * Decimal(3)
>>> d3 < Decimal(1)
True

非常令人失望,我回到文档中并继续阅读:

算术上下文是一个指定精度的环境[…]

好的,所以实际上有精度。可以复制经典问题:

>>> dd = d * 10**20
>>> dd
Decimal('33333333333333333333.33333333')
>>> for i in range(10000):
...    dd += 1 / Decimal(10**10)
>>> dd
Decimal('33333333333333333333.33333333')

所以, 我的问题是: 有没有办法让精度无限的小数类型?如果不是,比较2个十进制数字的更优雅的方法是什么(例如,如果增量小于精度,则d3
<1应该返回False)。

当前,当我只进行除法和乘法运算时,我使用以下Fraction类型:

>>> from fractions import Fraction
>>> f = Fraction(1) / Fraction(3)
>>> f
Fraction(1, 3)
>>> f * 3 < 1
False
>>> f * 3 == 1
True

这是最好的方法吗?还有其他选择吗?


问题答案:

Decimal类最适合于财务类型加法,减法乘法,除法类型问题:

>>> (1.1+2.2-3.3)*10000000000000000000
4440.892098500626                            # relevant for government invoices...
>>> import decimal
>>> D=decimal.Decimal
>>> (D('1.1')+D('2.2')-D('3.3'))*10000000000000000000
Decimal('0.0')

分数模块与您描述的有理数问题域配合良好:

>>> from fractions import Fraction
>>> f = Fraction(1) / Fraction(3)
>>> f
Fraction(1, 3)
>>> f * 3 < 1
False
>>> f * 3 == 1
True

对于用于科学工作的纯多精度浮点,请考虑使用mpmath。

如果您的问题可以解决符号问题,请考虑sympy。这是您处理1/3问题的方法:

>>> sympy.sympify('1/3')*3
1
>>> (sympy.sympify('1/3')*3) == 1
True

Sympy将mpmath用于任意精度的浮点,包括以符号方式处理有理数和无理数的能力。

考虑无理值√2的纯浮点表示形式:

>>> math.sqrt(2)
1.4142135623730951
>>> math.sqrt(2)*math.sqrt(2)
2.0000000000000004
>>> math.sqrt(2)*math.sqrt(2)==2
False

与sympy比较:

>>> sympy.sqrt(2)
sqrt(2)                              # treated symbolically
>>> sympy.sqrt(2)*sympy.sqrt(2)==2
True

您还可以减少值:

>>> import sympy
>>> sympy.sqrt(8)
2*sqrt(2)                            # √8 == √(4 x 2) == 2*√2...

但是,如果不小心,您会看到Sympy的问题类似于直线浮点:

>>> 1.1+2.2-3.3
4.440892098500626e-16
>>> sympy.sympify('1.1+2.2-3.3')
4.44089209850063e-16                   # :-(

最好用Decimal完成:

>>> D('1.1')+D('2.2')-D('3.3')
Decimal('0.0')

或使用小数或Sympy并保留诸如1.1比率之类的值:

>>> sympy.sympify('11/10+22/10-33/10')==0
True
>>> Fraction('1.1')+Fraction('2.2')-Fraction('3.3')==0
True

或在sympy中使用Rational:

>>> frac=sympy.Rational
>>> frac('1.1')+frac('2.2')-frac('3.3')==0
True
>>> frac('1/3')*3
1

您可以和sympy
live
一起玩。



 类似资料:
  • 类初始化规则规定:如果由于访问静态字段而触发类初始化,则只初始化声明了静态字段的类,即使静态字段被子类、子接口的类型或接口的实现类引用,也不会触发超类或子类的初始化。然后在下面的代码中,只应打印“初始化超类”。 } 当我运行这个时,输出:

  • 我希望下面的代码中有,但它运行良好。 根据JavaDoc for: 这个类的所有“Collection view Methods”返回的迭代器都是快速失败的:如果在迭代器创建后的任何时候,以任何方式(除了通过迭代器自己的remove方法)修改了映射,则迭代器将抛出一个ConcurrentModificationException。 因此,由于我在获得之后修改了,所以我应该得到。为什么不扔?

  • 问题内容: 我有一张桌子Table1 当我使用以下查询查询该表时 我得到的输出为 但是以同样的方式,当我使用以下查询时,我没有任何输出。 有人请给我指导,为什么它会那样工作,以及如何使用rownum。 问题答案: 汤姆回答了许多与Oracle有关的问题 简而言之,在应用where子句之后和应用order by子句之前,rownum可用。 在RowNum = 2的情况下,where子句中的谓词将永远

  • 所以这段时间我一直认为递归的问题是理解案例。事实证明,我的问题是理解递归案例的值。例如,向后打印数组的一部分。 原始尝试 一次有效的尝试 然而,这是一种高效的递归吗?还是有更好的办法?这是我从写出来的时候看出来的唯一方法。

  • 目前,在单元测试中,我有一个循环可以循环到1000次,如果分数没有更新,那么我假设这个数字可以连续滚动1000次,这是不可能的!不过,我凭空选择了1000这个数字。我想根据Java的随机类的实际行为选择一个更准确的数字。 从读到它所说的API时,它说它是“一个线性同余伪随机数生成器..”。我试图确定的是,基于它使用一个48位,是否有几次相同的值是不可能重复的。例如。在我的场景中,数字1-6可以生成

  • 我正在Swing上阅读。我很难理解这一段:首先,作者说 组件可以放置在面板等容器内。容器本身可以放在其他容器中,因此类容器扩展了组件。图9.8显示了组件的继承层次结构, 注意:不幸的是,继承层次结构在两个方面有些不干净。首先,顶级窗口,如JFrame,是container的子类,因此也是Component的子类,但它们不能放在其他容器内。而且,JComponent是Container的子类,而不是