【问题标题】:Significant figures in the decimal module十进制模块中的有效数字
【发布时间】:2025-11-21 09:35:01
【问题描述】:

所以我决定尝试通过编写一些 python 脚本来解决我的物理作业来为我解决问题。我遇到的一个问题是重要的数字似乎并不总是正确地出现。例如,这可以正确处理有效数字:

from decimal import Decimal
>>> Decimal('1.0') + Decimal('2.0')
Decimal("3.0")

但这不是:

>>> Decimal('1.00') / Decimal('3.00')
Decimal("0.3333333333333333333333333333")

所以两个问题:

  1. 我认为这不是预期的有效数字数量是正确的,还是我需要复习有效数字数学?
  2. 有什么方法可以做到这一点而无需手动设置小数精度?当然,我确信我可以使用 numpy 来执行此操作,但出于好奇,我只想知道是否有办法使用 decimal 模块执行此操作。

【问题讨论】:

    标签: python floating-point decimal physics significance


    【解决方案1】:

    将十进制工作精度更改为 2 位不是一个好主意,除非您绝对只打算执行单个操作。

    您应该始终以高于显着性水平的精度执行计算,并且只对最终结果进行四舍五入。如果您执行一长串计算并在每一步四舍五入到有效位数,则会累积错误。十进制模块不知道任何特定操作是长序列中的一个还是最终结果,因此它假定它不应该超过必要的舍入。理想情况下,它会使用无限精度,但这太昂贵了,因此 Python 开发人员选择了 28 位。

    一旦你得到最终结果,你可能想要的是量化:

    >>> (Decimal('1.00') / Decimal('3.00')).quantize(Decimal("0.001")) 十进制(“0.333”)

    您必须手动跟踪重要性。如果要自动进行重要性跟踪,则应使用区间算术。有一些可用于 Python 的库,包括 pyintervalmpmath(支持任意精度)。使用小数库实现区间算术也很简单,因为它支持定向舍入。

    您可能还想阅读Decimal Arithmetic FAQ: Is the decimal arithmetic ‘significance’ arithmetic?

    【讨论】:

    • 300/100 怎么样?您的代码将错误地导致 3.000
    【解决方案2】:

    小数不会像那样丢掉小数位。如果您真的想将精度限制为 2 d.p.那就试试吧

    decimal.getcontext().prec=2
    

    编辑:您也可以在每次乘法或除法时调用 quantize()(加法和减法将保留 2 dps)。

    【讨论】:

    • 嗯...所以没有办法让它做到这一点而不需要我手动设置精度?
    【解决方案3】:

    只是出于好奇...有必要使用十进制模块吗?当您准备好查看浮点数时,为什么不使用有效数字四舍五入的浮点数呢?或者您是否尝试跟踪计算的重要数字(例如,当您必须对结果进行误差分析时,将计算误差作为计算中不确定性的函数来计算)?如果您想要一个从数字左侧而不是右侧四舍五入的舍入函数,请尝试:

    def lround(x,leadingDigits=0): 
        """Return x either as 'print' would show it (the default) 
        or rounded to the specified digit as counted from the leftmost 
        non-zero digit of the number, e.g. lround(0.00326,2) --> 0.0033
        """ 
        assert leadingDigits>=0 
        if leadingDigits==0: 
                return float(str(x)) #just give it back like 'print' would give it
        return float('%.*e' % (int(leadingDigits),x)) #give it back as rounded by the %e format  
    

    当您打印它们或将它们转换为字符串时,这些数字看起来是正确的,但是如果您在提示符下工作并且没有明确地打印它们,它们可能看起来有点奇怪:

    >>> lround(1./3.,2),str(lround(1./3.,2)),str(lround(1./3.,4))
    (0.33000000000000002, '0.33', '0.3333')
    

    【讨论】:

      【解决方案4】:

      十进制默认为 28 位精度。
      限制它返回的位数的唯一方法是改变精度。

      【讨论】:

      • 不一定总是如此。例如: >>> Decimal('1.0') * Decimal('1.0') 产生 Decimal("1.00") 你是不是在除法的上下文中这么说?
      【解决方案5】:

      浮点有什么问题?

      >>> "%8.2e"%  ( 1.0/3.0 )
      '3.33e-01'
      

      它专为有效数字数量有限的科学式计算而设计。

      【讨论】:

      • 问题是我仍然需要手动设置有效位数。
      • 我确实不明白设置有效数字是一个问题。您必须扩展您的问题以显示您想要什么以及为什么您不能/不想设置有效数字。
      【解决方案6】:

      如果我正确理解了小数,“精度”是十进制表示法中小数点后的位数。

      您似乎想要别的东西:有效数字的数量。这比科学记数法中小数点后的位数多一。

      我有兴趣了解一个 Python 模块,它可以进行有效数字感知的浮点计算。

      【讨论】: