Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/287.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
比较python中的小数_Python_Testing_Decimal - Fatal编程技术网

比较python中的小数

比较python中的小数,python,testing,decimal,Python,Testing,Decimal,我希望能够在Python中比较小数。为了用钱计算,聪明的人告诉我用小数代替浮点数,所以我就这么做了。但是,如果我想验证一个计算是否产生了预期的结果,我将如何进行呢 >>> a = Decimal(1./3.) >>> a Decimal('0.333333333333333314829616256247390992939472198486328125') >>> b = Decimal(2./3.) >>> b Decima

我希望能够在Python中比较小数。为了用钱计算,聪明的人告诉我用小数代替浮点数,所以我就这么做了。但是,如果我想验证一个计算是否产生了预期的结果,我将如何进行呢

>>> a = Decimal(1./3.)
>>> a
Decimal('0.333333333333333314829616256247390992939472198486328125')
>>> b = Decimal(2./3.)
>>> b
Decimal('0.66666666666666662965923251249478198587894439697265625')
>>> a == b
False
>>> a == b - a
False
>>> a == b - Decimal(1./3.)
False
在这个例子中,a=1/3,b=2/3,很明显,b-a=1/3=a,但这不能用小数来完成

我想这样做的一种方式是,我希望结果是1/3,在python中,我这样写

Decimal(1./3.).quantize(...)
然后我可以这样比较:

(b-a).quantize(...) == Decimal(1./3.).quantize(...)
>>> from fractions import Fraction
>>> a = Fraction(1,3)
>>> a
Fraction(1, 3)
>>> b = Fraction(2,3)
>>> b
Fraction(2, 3)
>>> a == b
False
>>> a == b - a
True
>>> a + b == Fraction(1, 1)
True
>>> 2 * a == b
True

所以,我的问题是:有没有更干净的方法?您将如何编写小数测试?

您使用的方法不正确

>>> from decimal import *

>>> Decimal(1./3.)                  # Your code
Decimal('0.333333333333333314829616256247390992939472198486328125')

>>> Decimal("1")/Decimal("3")       # My code
Decimal('0.3333333333333333333333333333')
在“您的代码”中,您实际上执行“经典”浮点除法——然后将结果转换为十进制。浮点引入的错误会传播到小数点

在“我的代码”中,我进行十进制除法。生成正确(但截断)的结果,直到最后一位


关于四舍五入。如果您处理货币数据,您必须了解业务中四舍五入的规则。如果不是这样,使用
Decimal
不会自动解决所有问题。以下是一个例子:3名股东之间的股份为100美元

>>> TWOPLACES = Decimal(10) ** -2

>>> dividende = Decimal("100.00")
>>> john = (dividende / Decimal("3")).quantize(TWOPLACES)
>>> john
Decimal('33.33')
>>> paul = (dividende / Decimal("3")).quantize(TWOPLACES)
>>> georges = (dividende / Decimal("3")).quantize(TWOPLACES)
>>> john+paul+georges
Decimal('99.99')

Oups:缺少0.01美元(给银行的免费礼物?

浮点运算不准确:

十进制数字可以精确表示。相比之下,数字像 1.1和2.2没有二进制浮点的精确表示。最终用户通常不希望
1.1+2.2
显示为
3.30000000000000003
与二进制浮点一样

您必须选择一个分辨率并截断超过该分辨率的所有内容:

>>> from decimal import *
>>> getcontext().prec = 6
>>> Decimal(1) / Decimal(7)
Decimal('0.142857')
>>> getcontext().prec = 28
>>> Decimal(1) / Decimal(7)
Decimal('0.1428571428571428571428571429')

很明显,您会得到一些舍入误差,这些误差会随着操作次数的增加而增加,因此您必须仔细选择您的分辨率。

您的长篇大论中说明了您希望进行货币计算,同时注意舍入误差。小数是一个很好的选择,因为它们在与其他小数进行加法、减法和乘法运算时会产生精确的结果

奇怪的是,您的示例显示如何使用分数“1/3”。我从来没有在我的银行里存过整整三分之一美元。。。这是不可能的,因为没有这样的货币单位

我的观点是,如果你在做任何分工,那么你需要了解你在做什么,组织在这类事情上的政策是什么。。。在这种情况下,应该可以实现您想要的十进制量化

现在--如果你真的想对小数进行除法,并且你想进行任意的“精确性”,你真的不想使用
Decimal
对象您想使用
分数
对象。

这样,您的示例将如下所示:

(b-a).quantize(...) == Decimal(1./3.).quantize(...)
>>> from fractions import Fraction
>>> a = Fraction(1,3)
>>> a
Fraction(1, 3)
>>> b = Fraction(2,3)
>>> b
Fraction(2, 3)
>>> a == b
False
>>> a == b - a
True
>>> a + b == Fraction(1, 1)
True
>>> 2 * a == b
True
好的,甚至还有一个警告:
分数
对象是两个整数的比率,所以你需要乘以10的右幂,然后进行特殊处理

听起来好像工作太多了?对可能是吧


所以,回到十进制对象;对十进制除法和十进制乘法进行量化/舍入。

还有另一种方法可能适合您:

  • 继续以浮点值进行所有计算
  • 当您需要比较是否相等时,请使用
    round(val,places)
例如:

>>> a = 1./3
>>> a
0.33333333333333331
>>> b = 2./3
>>> b
0.66666666666666663
>>> b-a
0.33333333333333331
>>> round(a,2) == round(b-a, 2)
True
如果愿意,创建一个函数
等于分()


这是有道理的。但是仍然需要截断/量化结果,以便进行适当的比较?@Eldamir我已经用一些与比较相关的元素更新了答案。对于货币值,您将把所有结果截断/四舍五入到“点”后的固定小数位数。通常是2,但也有4到5。不管怎样,你应该有一些明确的规则,否则你最终会得到美分的“浮动”——就像《超人3:D》