在Python 2.5到2.7中,十进制除法结果无效

12 投票
2 回答
926 浏览
提问于 2025-04-17 03:18

我仔细阅读了Python的decimal模块文档,但对于在进行小数除法时发生了什么,我还是感到困惑。

在Python 2.4.6中,结果是可以理解的:

>>> import decimal
>>> decimal.Decimal(1000) / 10
Decimal("100")

但是在Python 2.5.6、2.6.7和2.7.2中,结果就让人摸不着头脑了:

>>> import decimal
>>> decimal.Decimal(1000) / 10
Decimal('0.00000-6930898827444486144')

更让人困惑的是,这个结果看起来似乎都不正确:

>>> decimal.Decimal('0.00000-6930898827444486144')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/decimal.py", line 548, in __new__
    "Invalid literal for Decimal: %r" % value)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/decimal.py", line 3844, in _raise_error
    raise error(explanation)
decimal.InvalidOperation: Invalid literal for Decimal: '0.00000-6930898827444486144'

使用decimal.Decimal(1000) / decimal.Decimal(10)得到的结果也是一样的,所以这并不是因为用整数作为除数的问题。

问题的一部分显然是关于精度的:

>>> decimal.Decimal("1000.000") / decimal.Decimal("10.000")
Decimal('0.00000-6930898827444486144')
>>> decimal.Decimal("1000.000") / decimal.Decimal("10")
Decimal('0.000200376420520689664')

但是在decimal.Decimal("1000.000")中应该有足够的精度来安全地除以10,并得到一个至少在合理范围内的答案。

这个行为在Python的三个主要版本中都没有变化,这让我觉得这不是一个错误。

我到底做错了什么?我漏掉了什么?

我该如何进行小数除法(除了使用Python 2.4)?

2 个回答

0

仅供参考:对于在OS X上通过Homebrew使用clang编译的Python 2.7.3,这个问题似乎已经解决了。

Python 2.7.3 (default, Oct 10 2012, 13:00:00) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import decimal
>>> decimal.Decimal(1000) / 10
Decimal('100')
7

根据你在MacPorts上遇到的bug,你安装了Xcode 4,而你的Python 2.7.2是用clang这个C编译器构建的,而不是gcc-4.2。其实在OS X上,用clang构建时有一个已知的问题,这个问题在2.7.2版本之后的Python中已经修复了。你可以选择应用补丁,或者更好的办法是确保构建时使用gcc-4.2。像这样做(未经测试!):

sudo bash
export CC=/usr/bin/gcc-4.2
port clean python27
port upgrade --force python27

在构建之前,可能会有效,如果MacPorts没有覆盖它的话。

更新:现在所需的补丁已经应用到Python 2的MacPorts端口文件中了。详情请见 https://trac.macports.org/changeset/87442

撰写回答