那么`decimal.Decimal(1.0/3.0)`中的27位额外精度?

kjo*_*kjo 4 python floating-point decimal

这篇文章是关于表达式中有效位数decimal.Decimal(1.0/3.0).

decimal.Decimal"新的十进制的重要性仅由输入的位数确定"的文档.

由此我认为,有效位数decimal.Decimal(1.0/3.0)应该由操作产生的IEEE 754双倍有效位数确定1.0/3.0.

现在,我的理解是IEEE 754 64位双精度具有" 15-17有效十进制数字精度 ".

因此,综合以上所有内容,我预计decimal.Decimal(1.0/3.0)最多只能得到17位有效小数.

但是,似乎decimal.Decimal(1.0/3.0)至少给出了54位有效小数位:

import decimal
print decimal.Decimal(1.0/3.0)

# 0.333333333333333314829616256247390992939472198486328125
Run Code Online (Sandbox Code Playgroud)

所有这些都归结为两个关键问题:

  1. IEEE 754双倍具有"15-17有效十进制数字精度"的主张是什么?
  2. 如何解决以下几项之间的矛盾?:
    1. decimal.Decimal上面引用的文档
    2. 中的54位(或更多)有效数字 decimal.Decimal(1.0/3.0)
    3. IEEE 754 double中有效十进制数字的最大值为17.

附录:好的,我现在对情况有了更好的了解,感谢ajcr的回答以及其他一些评论.

在内部,decimal表示1.0/3.0为分数

6004799503160661/18014398509481984
Run Code Online (Sandbox Code Playgroud)

该分数的分母是2 54.的分子是(2 54 - 1)/ 3,准确.

这部分的十进制表示是完全正确的

0.333333333333333314829616256247390992939472198486328125
Run Code Online (Sandbox Code Playgroud)

附录2: 再试一次.浮点数F是不可数的实数的替代.该组值包括由浮点数F 精确表示的有理数Q(F).它还包括在Q(F)之上和之下的不可忽略的许多实际值.现在,给定64位IEEE 754双精度范围内的实数R,让F(R)成为R被表示为浮点数1时映射到的双精度.

例如,如果R = 1/3,则F(R)是由以下64位给出的IEEE 754 double:

0 01111111101 0101010101010101010101010101010101010101010101010101 = F(R)
Run Code Online (Sandbox Code Playgroud)

...和Q(˚F([R ))是分数Ñ/d,其中,d = 2 54 = 18014398509481984,和Ñ =(2 54 - 1)/ 3 = 6004799503160661.简而言之:

6004799503160661/18014398509481984 = Q(F(R))
Run Code Online (Sandbox Code Playgroud)

或者,作为精确的小数:

0.333333333333333314829616256247390992939472198486328125 = Q(F(R))
Run Code Online (Sandbox Code Playgroud)

但浮点F(R)不仅代表R = 1/3和Q(F(R))= N/D,而且代表范围(A,B)2中的所有实数,其中A =(2 ñ - 1)/ 2 d,及 =(2 ñ + 1)/ 2 d.下面我展示了A < Q(F(R))< B精确十进制表示,以及R = 1/3 的54位不精确表示:

0.3333333333333332593184650249895639717578887939453125   = A
0.333333333333333314829616256247390992939472198486328125 = Q(F(R))
0.333333333333333333333333333333333333333333333333333333 ~ R
0.33333333333333337034076748750521801412105560302734375  = B
Run Code Online (Sandbox Code Playgroud)

现在,这里是相同的四个数字A,Q(F(R)),RB的十进制表示,但现在舍入到17个有效数字:

0.33333333333333326 ~ A
0.33333333333333331 ~ Q(F(R))
0.33333333333333333 ~ R
0.33333333333333337 ~ B
Run Code Online (Sandbox Code Playgroud)

这至少应该解释为什么IEEE 754双打据说具有"15-17有效十进制数字精度".更明确地,由给定IEEE 754双精度表示的任何两个数的十进制表示将在其最重要数字的15到17之间达成一致.

好的,回到Q(F(R)).是的,这是一个有理数,其分母是2的幂,因此我们可以精确地计算其十进制扩展.这次扩张的重要数字实际上是无限的.但是这个数字在这里的作用严格地说是一组不可数的实数的规范代表,所有这些数字共有17个有效数字.因此,在Q(F(R))的扩展中使用任何更重要的数字相当于对这组实数的误解.在这个意义上,Q(F(R))的十进制扩展中最不重要的27个数字,就Q(F(R))作为一个立场的作用而言,是无关的,无关紧要的,实际上并不重要.在用于所有数字(,),包括- [R .

换句话说,当作为区间(A,B)的代表时,Q(F(R))应该只是

0.33333333333333331 ~ Q(F(R))
Run Code Online (Sandbox Code Playgroud)

其十进制扩展的其余部分与此角色没有密切关系,因此,它应该被排除在视野之外.

我意识到,考虑到decimal对它的所有要求,设计可能比它更好.以下,实际上,上述虚假陈述可能是不可避免的.但是,至少应该清楚地记录下来,以及与浮点数相关的所有其他或多或少不可避免的错误陈述.


1是的,我保持IEEE 754双F(R)(存储器中的特定位序列)和有理数Q(F(R))(数学实体)之间的区别,只是为了绝对清楚.

2我想它也包括这个范围的一个端点,但这个细节在这里并不重要.

Ale*_*ley 5

传递一个float时,Decimal使用from_float构造函数.这个类方法完全从单个Python float构造一个Decimal ; 它不知道浮点数是如何计算的,人类可能认为它只是精确到一定数量的数字.

相反,它通过将浮点数视为两个整数的比率来确定从浮点数中获取的适当数字位数.这是在740行:

n, d = abs(f).as_integer_ratio()
k = d.bit_length() - 1
result = _dec_from_triple(sign, str(n*5**k), -k)
Run Code Online (Sandbox Code Playgroud)

这意味着1.0/3.0我们有以下内容:

>>> f = 1.0 / 3.0
>>> f.as_integer_ratio()
(6004799503160661, 18014398509481984)
>>> (18014398509481984).bit_length()
55
Run Code Online (Sandbox Code Playgroud)

为了构造小数,计算符号,系数和指数并传递给_dec_from_triple.在这种情况下,系数是字符串:

'333333333333333314829616256247390992939472198486328125'
Run Code Online (Sandbox Code Playgroud)

和指数是-(55-1).这给小数点后精确到54位数的小数点,因此您的观察结果.