如何打印浮点数的完整精度

13
我写了以下函数,其中传递了x和y的值:
def check(x, y):
    print(type(x))
    print(type(y))
    print(x)
    print(y)
    if x == y:
        print "Yes"

现在当我调用 check(1.00000000000000001, 1.0000000000000002) 它会打印:

<type 'float'>
<type 'float'>
1.0
1.0

现在,通过变量x和y的打印语句,很难调试为什么x != y(尽管它们都打印相同的值)。尽管我通过打印x - y解决了这个问题,但是否有任何方法可以修改打印语句,以便在这种特定用例中知道为什么x!= y,而不使用任何外部打印库或减法解决方案。

我正在使用Python 2.7。 - skaul05
1
这个问题不是链接问题的重复。链接问题要求打印固定小数位数。这个问题搜索一种可能性,以获得具有完全精度的字符串表示,但不一定是固定小数位数。这是一个巨大的区别,另一个问题中的解决方案('{0:.16f}'.format(1.6))根本无法实现这个目的,例如 1e-3002e-300 具有相同的固定小数字符串表示,并且不能满足“完全精度”。 - bluenote10
我已经找到了解决方案,但是由于错误的重复标记,我无法将其发布在任何地方... - bluenote10
4个回答

8
为了获得完整的精度和正确的格式,请执行以下操作:
format(2**(1/2), '.60g') 
# -> '1.4142135623730951454746218587388284504413604736328125'

并使用以下方式进行检查

import decimal
print(decimal.Decimal.from_float(2**(1/2))
# -> '1.4142135623730951454746218587388284504413604736328125'

g格式类型可以在需要时切换到指数表示法。


1
这个答案生成了一个字符串表示,使用比IEEE标准要求的更多的数字(浪费空间超过2倍)。请参考我的答案,生成一个产生最小字面值表示浮点数的字符串表示。 - bluenote10

7
更新: 在Python 3中,对float类型的str函数保证产生带有完整精度的字符串文字。

在Python 2中不是这种情况。例如str(1.0000000000000002)在Python 2中为'1.0',而在Python 3中它会给出'1.0000000000000002',如预期。

这经常是混淆的根源,因为简单的print(x)可能没有打印出完整精度的x,导致错误的结论,就像问题的例子一样。

有关此更改的背景,请参见此处


Python 2解决方案

获取具有完整精度的浮点数字符串表示的简单解决方案是使用reprjson.dumps

JSON序列化/反序列化必须确保往返均不丢失,因此,实现会生成您要查找的字符串表示形式:

def check(x, y):
    print(repr(x))
    print(repr(y))
    print("x == y is {}".format(x == y))

In [1]: check(1.00000000000000001, 1.0000000000000002)
1.0
1.0000000000000002
x == y is False

In [2]: check(1e-300, 2e-300)
1e-300
2e-300
x == y is False

In [3]: check(1e+300, 2e+300)
1e+300
2e+300
x == y is False

这也说明了1.00000000000000001实际上等于1.0。可以使用np.nextafter列举围绕1.0的数字,以检查这一点,它会生成下一个更大/更小的可表示浮点数值:
    0.9999999999999994
    0.9999999999999996
    0.9999999999999997
    0.9999999999999998
    0.9999999999999999
[*] 1.0               
    1.0000000000000002
    1.0000000000000004
    1.0000000000000007
    1.0000000000000009
    1.000000000000001 

回复@Robert:

json.dumps在您的情况下也可以使用。使用'.60g'格式化只是产生一个文字,含有比IEEE双精度浮点数能够保存的更多不必要的数字。由json.dumps生成的另一个文字的精度足以表示该特定浮点数,您可以通过以下方式进行检查:

enter image description here

最接近于1./math.sqrt(3.)的两个IEEE文字为:

enter image description here

第一个是已经最接近的可能表示,存储更多数字的1./math.sqrt(3.)将始终返回相同的数字。

json.dumps对于64位IEEE浮点数具有无损往返,因此它保证所产生的数字位数足够。


json.dumps 对我来说实际上不起作用。 json.dumps(1./math.sqrt(3.)) 打印出 0.5773502691896258,而 format(1./math.sqrt(3.), '.60g') 则打印出 0.57735026918962584208117050366126932203769683837890625。 - Robert Andreas Fritsch
1
@RobertAndreasFritsch 在这种情况下,json.dumps 文本的精度也足够了。我在答案中添加了一些解释。希望能有所帮助。 - bluenote10
1
在Python 3.10.5上,str(0.1)似乎无法打印完整的精度。 - Felix Bertoni
1
@bluenote10 哦,我的错!我把完整精度和确切值搞混了--'也许你可以编辑你的帖子,让别人清楚明白?这会很好! - Felix Bertoni
1
@JosephGarvin 在存储浮点数时,会发生某种舍入。因此,在内存中,0.1并不是精确的0.1,而是一个接近的值X。如果我们将X以“完全精度”的形式打印为0.1,则意味着X是0.1的FP表示法。如果我们将0.1转换回来,就会回到存储在FP中的X。另一方面,“精确值”实际上意味着打印X,即存储的精确值,而不是0.1或其他映射到它的值之一。 - Felix Bertoni
显示剩余5条评论

1

在这里,你真正需要的是小数。Python float 不允许你达到如此高的精度。

In [28]: d= Decimal('1.00000000000000001')

In [29]: print d
1.00000000000000001

1
在Python中,不需要小数点,浮点值可以以完整精度打印。 - bluenote10

-1

这里讨论了一个类似情况的解决方案: 打印浮点数,包括尾随0的n位小数

不过我不知道是否有一种方法可以打印出完整长度的浮点数。但我猜如果你在小数点后使用100个值,它将解决大部分问题。


1
在这种情况下,我必须事先提到最大的小数位数,但在某些情况下可能会失败。 - skaul05
字符串格式化在这里无法帮助: print '{:.20f}'.format(1.00000000000000001) -> 1.00000000000000000000 - Smooth Fire
@RadosławGanczarek 这是因为这个值确实恰好为1。但请注意,OP示例中的1.0000000000000002少了一个零位,而'{:.20f}'.format(1.0000000000000002)返回1.00000000000000022204 - bluenote10

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接