【问题标题】:Rounding errors in pythonpython中的舍入错误
【发布时间】:2012-07-24 20:20:28
【问题描述】:

为什么乘法的顺序会影响结果?考虑以下代码

a=47.215419672114173
b=-0.45000000000000007
c=-0.91006620964286644
result1=a*b*c
temp=b*c
result2=a*temp
result1==result2

我们都知道 result1 应该等于result2,但是我们得到:

result1==result2 #FALSE!

差别很小

result1-result2 #3.552713678800501e-15

但是,对于特定应用程序,此错误可能会放大,因此执行相同计算的两个程序(一个使用结果1,另一个使用结果2)的输出可能完全不同。

为什么会这样?可以做些什么来解决大量数值/科学应用中的此类问题?

谢谢!

更新

很好的答案,但我仍然想念为什么乘法的顺序很重要的原因,例如

temp2=a*b
result3=temp2*c
result1==result3 #True

所以编译器/解释器似乎将 a*b*c 视为 (a*b)*c

【问题讨论】:

  • 比较机器表示的浮点数的 exact 相等性会让宇宙不开心,我的朋友。
  • @Mannaggia - 这里有一些链接可能有助于理解您注意到的行为:The Perils of Floating Point, Floating Point Arithmetic: Issues and Limitations
  • @Marcin:好的,但是如果一个人只能在他/她掌握的领域提问,那么这个博客的作用是什么?我的问题是关于操作的 排序 以及这如何影响精度,我知道实数不能用二进制形式表示,这与任何 IEEE 无关标准(这只是一个约定),但二进制(或三进制,如果你想)编码系统。
  • @Marcin 他最初的问题是教科书中没有列出的——如果他甚至知道在哪里可以找到这些信息——因为他的问题是为什么一组计算他认为在哪里执行相同的硬件操作会产生略微不同的结果。答案需要了解操作顺序和硬件不准确性。对我来说,这似乎是一个非常合理的问题。

标签: python rounding numerical-computing


【解决方案1】:

在将浮点数从十进制表示形式转换为二进制表示形式时,所有编程语言都会丢失精度。这会导致计算不准确(至少从以 10 为底的角度来看,因为数学实际上是在以二进制表示的浮点值上完成的),包括运算顺序改变结果的情况。大多数语言都提供了一种数据结构来保持以 10 为底的精度,但会以性能为代价。在 Python 中查看Decimal

编辑:

回答您的更新,不完全是。计算机按顺序做事,因此当您为它们提供一系列操作时,它们会按顺序逐一进行。除了顺序命令处理之外,没有明确的操作顺序。

【讨论】:

  • 作为浮点错误的示例,请尝试1-0.9。结果是0.09999999999999998,而不是0.1
  • “这会导致计算不准确” 吹毛求疵,我不会说计算不准确,而是说它们只是用实数计算的近似值。
  • @sr2222 实际上好多了。
【解决方案2】:

每次乘法的结果是原始数字的两倍,并且需要进行四舍五入,以使其适合为浮点数分配的空间。当您重新排列顺序时,这种舍入可能会改变结果。

【讨论】:

  • 谢谢,这在概念上回答了关键问题,但也感谢@sr2222,可惜只有一个正确答案:-)
  • @Mannaggia,我的回答是正确的,即使这些值可以用二进制精确表示。
  • 是的,因为当计算结果放回内存时,由于位数较少而导致精度损失,对吧?
  • @Mannaggia,它与内存无关,它是处理器本身可用的位数。例如,x86 上的浮点值可以在有效位中保存 53 位,但乘法运算会产生 106 位。内部寄存器可以保存 64 位有效位,但这还不够,结果必须在写入内存之前进行四舍五入。
【解决方案3】:

在任何编程语言中使用浮点数时,都会丢失精度。您可以:

适应精度损失,并相应地调整您的相等检查,如下所示:

 are_equal = (result1-result2)>0.0001

其中 0.0001 (epsilon) 是您设置的值。

或者使用python自带的Decimal类,速度有点慢。

【讨论】:

  • +1 显示在 99% 的情况下应该如何进行浮点相等检查
【解决方案4】:

应该始终(由您)使用像 10^-10 这样的小 epsilon 进行浮点比较

【讨论】:

    【解决方案5】:

    我们都知道result1应该等于result2,但是我们得到:

    不,我们并不都知道。事实上,它们不应该相等,这就是它们不相等的原因。

    您似乎相信您正在使用实数。你不是 - 你正在使用 IEEE 浮点表示。他们不遵循相同的公理。他们不是一回事。

    操作的顺序很重要,因为 python 会评估每个表达式,这会产生一个浮点数。

    【讨论】:

    • 当然,我的意思是象征性地说这两个表达式是相等的
    • @Mannaggia 不,象征性地,这两个表达式不相等。这就是他们不平等的原因。再说一遍:您使用的不是实数。
    • 那么为什么这是真的:temp2=a*b result3=temp2*c result1==result3
    • @Mannaggia 这是真的,因为这些计算具有相同的结果。仅仅因为一个计算按照您认为应该的方式进行,并不意味着所有计算都应该按照您认为应该的方式进行。再一次,这些不是实数,对它们的运算不遵循相同的规律。
    • 仅仅因为一些浮点运算是可交换的,并不意味着所有都是。处理浮点数时,交换行为是目标,而不是保证。
    【解决方案6】:

    为什么: 可能您的机器/Python 无法处理这么多的准确度。 见:http://en.wikipedia.org/wiki/Machine_epsilon#Approximation_using_Python

    做什么: 这应该会有所帮助:http://packages.python.org/bigfloat/

    【讨论】:

      【解决方案7】:

      在计算机中表示数字是计算机科学的一个重要研究领域。这不是仅在 python 中存在的问题,而是任何编程语言都具有此属性,因为默认情况下执行任意精确的任何计算都太昂贵了。

      The numerical stability 的算法反映了在思考数值算法时的一些限制。如前所述,Decimal 被定义为在银行应用程序或任何可能需要它的应用程序中执行精确计算的标准。在python中,有一个implementation这个标准。

      【讨论】:

        【解决方案8】:

        正如之前的帖子中所回答的那样,这是编程语言中常见的浮点算术问题。您应该注意永远不要对 float 类型应用完全相等。

        当您进行此类比较时,您可以使用基于给定容差(阈值)进行比较的函数。如果数字足够接近,则应将它们视为数量相等。类似的东西:

        def isequal_float(x1,x2, tol=10**(-8)):
            """Returns the results of floating point equality, according to a tolerance."""
            return abs(x1 - x2)<tol
        

        会成功的。如果我没记错的话,确切的容差取决于 float 类型是单精度还是双精度,这取决于您使用的语言。

        使用这样的函数可以方便地比较计算结果,例如numpy。让我们以下面的示例为例,其中使用两种方法为具有连续变量的数据集计算相关矩阵:pandas 方法pd.DataFrame.corr()numpy 函数np.corrcoef()

        import numpy as np
        import seaborn as sns 
        
        iris = sns.load_dataset('iris')
        iris.drop('species', axis = 1, inplace=True)
        
        # calculate correlation coefficient matrices using two different methods
        cor1 = iris.corr().to_numpy()
        cor2 = np.corrcoef(iris.transpose())
        
        print(cor1)
        print(cor2)
        

        结果似乎相似:

        [[ 1.         -0.11756978  0.87175378  0.81794113]
         [-0.11756978  1.         -0.4284401  -0.36612593]
         [ 0.87175378 -0.4284401   1.          0.96286543]
         [ 0.81794113 -0.36612593  0.96286543  1.        ]]
        [[ 1.         -0.11756978  0.87175378  0.81794113]
         [-0.11756978  1.         -0.4284401  -0.36612593]
         [ 0.87175378 -0.4284401   1.          0.96286543]
         [ 0.81794113 -0.36612593  0.96286543  1.        ]]
        

        但它们完全相等的结果不是。这些运算符:

        print(cor1 == cor2)
        print(np.equal(cor1, cor2))
        

        将主要产生False 元素方面的结果:

        [[ True False False False]
         [False False False False]
         [False False False False]
         [False False False  True]]
        

        同样,np.array_equal(cor1, cor2) 也将产生 False。但是,自定义功能给出了您想要的比较:

        out = [isequal_float(i,j) for i,j in zip(cor1.reshape(16, ), cor2.reshape(16, ))]
        print(out)
        

        [True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True]

        注意:numpy 包含.allclose() 函数,用于在 numpy 数组中执行浮点逐元素比较。

        print(np.allclose(cor1, cor2))
        >>>True
        

        【讨论】:

          猜你喜欢
          • 2013-04-02
          • 2021-12-26
          • 2010-10-31
          • 1970-01-01
          • 2021-07-02
          • 2011-08-25
          相关资源
          最近更新 更多