【问题标题】:Unexpected floating-point representations in PythonPython中意外的浮点表示
【发布时间】:2012-06-29 19:42:04
【问题描述】:

您好,我正在使用 Python 中的字典来存储一些城市及其人口:

population = { 'Shanghai' : 17.8, 'Istanbul' : 13.3, 'Karachi' : 13.0, 'mumbai' : 12.5 }

现在如果我使用命令print population,我会得到结果:

{'Karachi': 13.0, 'Shanghai': 17.800000000000001, 'Istanbul': 13.300000000000001, 'mumbai': 12.5}

而如果我使用命令print population['Shanghai'],我会得到17.8 的初始输入。

我的问题是17.813.3 是如何分别变成17.80000000000000113.300000000000001 的?所有这些信息是如何产生的?以及为什么它存储在那里,因为我的初始输入表明我不需要那些额外的信息,至少据我所知。

【问题讨论】:

  • 字典对你来说并不是意外的行为。您刚刚遇到Floating Point 号码。

标签: python dictionary hashtable


【解决方案1】:

这已在 Python 3.1 中更改。来自what's new 页面:

Python 现在使用 David Gay 的算法来寻找最短的 不改变其值的浮点表示。这 应该有助于减轻围绕二进制浮动的一些混淆 点数。

使用1.1 之类的数字很容易看出其重要性 在二进制浮点中没有精确的等价物。既然有 没有确切的等价物,像float('1.1') 这样的表达式的计算结果为 最接近的可表示值,即十六进制 0x1.199999999999ap+01.100000000000000088817841970012523233890533447265625 十进制。 该最接近的值曾经并且仍然用于后续浮点 计算。

新的是数字的显示方式。以前,Python 使用 简单的方法。 repr(1.1) 的值计算为 format(1.1, '.17g'),其计算结果为 '1.1000000000000001'。的优势 使用 17 位数字是因为它依靠 IEEE-754 保证来确保 eval(repr(1.1)) 将精确地往返返回其原始值。 缺点是很多人发现输出很混乱 (误认为二进制浮点的内在限制 表示是 Python 本身的问题)。

repr(1.1) 的新算法更智能并返回'1.1'。 实际上,它搜索所有等效的字符串表示(那些 以相同的基础浮点值存储)并返回 最短的表示。

新算法倾向于在可能的情况下发出更清晰的表示, 但它不会改变基础价值。所以,还是这样 1.1 + 2.2 != 3.3 即使陈述可能暗示 否则。

新算法依赖于底层的某些特征 浮点实现。如果没有找到所需的功能, 旧算法将继续使用。此外,文本泡菜 协议通过使用旧的协议来确保跨平台的可移植性 算法。

(由 Eric Smith 和 Mark Dickinson 供稿;issue 1580

【讨论】:

    【解决方案2】:

    如果您想让小数点完全按照您在世界上任何机器上指定的方式表示,您必须使用 decimal.Decimal。

    有关信息,请参阅 Python 手册:http://docs.python.org/library/decimal.html

    >>> from decimal import Decimal
    >>> print Decimal('3.14')
    3.14
    

    【讨论】:

    • 注意事项 -- Decimals 仍然是浮点数,只是以 10 为底,而不是以 2 为底。
    【解决方案3】:

    您需要了解浮点数在计算机中的工作原理。

    基本上,并非所有十进制数字都可以精确存储,在这种情况下,您将获得最接近的数字。有时这种抽象会泄漏,您会看到错误。

    这可能是由于用于您描述的两个用例的打印逻辑不同。我无法重现该行为(在 Win64 中使用 Python 2.7.2)。

    如果你使用一个完全可表示的数字,比如1.5,我猜这个效果会消失。

    【讨论】:

    • 感谢您提供的信息。我想浮点数一定是这样。我会让这个答案保持开放状态,看看其他人是否会添加一些东西,一段时间,如果没有,我会关闭它。再次感谢。
    • 没什么可补充的,在这两点上展开都是正确的。当你“打印”字典时,你会得到浮点值的内部表示,而当你打印浮点值时,你会得到“字符串化”(四舍五入)版本。试试 "print repr(population["shangai"])" 和 "print str(population["shangai"])"...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-17
    • 2013-08-10
    • 1970-01-01
    • 2011-08-10
    • 2022-01-05
    • 1970-01-01
    • 2016-08-10
    相关资源
    最近更新 更多