【问题标题】:How a Python newbie might overcome problems with floating point comparisonsPython 新手如何克服浮点比较问题
【发布时间】:2014-04-01 21:08:59
【问题描述】:

抱歉,问题很长,代码不是真正的最小化。

我对浮点比较的棘手之处了解非常有限。 我已经阅读了一些关于该主题的 python 文档和教程。我已经阅读了一些 SO 讨论,例如 https://stackoverflow.com/a/4029397/1445400

但是,我不知道如何应用诸如“您为什么不使用 str(value)”或“仅使用 % 格式化它”或“您必须使用小数”之类的响应。我最喜欢的主题是“只需忽略小数点后 11 位的差异......它们并不重要,如果将响应格式化为字符串,您最终可以获得正确的美学。”我不知道如何在我的应用程序中使用它。

这是我的代码,可能看起来像家庭作业,但实际上并非如此。我正在计算跨越非矩形多边形的线网格的交点。我生成一个矩形,移动一个或多个角,然后在多边形上绘制和重绘网格,因此我需要计算网格线的起点、终点和交叉点。

def partition_boundaries(start, stop, number_of_partitions):
    interval = (stop - start)/number_of_partitions
    l = [start, stop]
    i = 1
    while i < number_of_partitions:
        l.insert(i, start + i*interval)
        i += 1
    return l

def test():
    test_cases = [
                  ((0.0, 1.0, 2), [0, .5, 1]), 
                  ((0.0, 1.0, 4), [0.0, 0.25, 0.5, 0.75, 1.0]), 
                  ]
    passes = 0
    for (args, expected_result) in test_cases:
        result = partition_boundaries(*args)
        if result != expected_result:
            print "Failed for: ", args, ".  Expected: ", expected_result, " Got: ", result
        else:
            passes = passes + 1
    print passes, " out of ", len(test_cases), " test cases passed."

test()

这会产生如下输出: 失败: (0.0, 1.0, 4) 。预期:[0.0, 0.25, 0.5, 0.75000000000000011, 1.0] 得到:[0.0, 0.25, 0.5, 0.75, 1.0]

令人沮丧的是,相信这么简单的事情需要神秘的操作,例如将数字转换为字符串然后再返回,或者编写我自己的函数来将差异的绝对值与容差进行比较等等。“这不应该这么难”,但也许我需要克服自己。这也让我对到达一个可以“温和地”向我的孩子介绍“真正的”编程的地方感到紧张。

我不是做财务会计的,不需要很多很多重要的数字。

对于这段代码,你建议我如何继续我的初学者教育?

【问题讨论】:

    标签: python floating-point


    【解决方案1】:

    浮点相等性测试是一件困难的事情。我不知道 Python 中有什么东西会改变语言中内置的基本浮点比较,但你可以编写一个函数,如果两个数字接近,则返回 True,其中接近可以用相对或绝对术语定义,例如

    def almost_equal(x,y):
        epsilon = 0.00001
        return abs(x-y) < epsilon
    

    然后您将编写另一个函数来测试结构的“相等性”,使用almost_equal 代替== 进行任何浮点比较。

    【讨论】:

      【解决方案2】:

      理解浮点并不难。有两件事要记住: 1) 就像在计算器中一样,您只有有限的位数(通常在 16 位左右)。 2) 增量不是以小数为单位,而是以binary 为单位。借助Numpy,可以轻松确定不同值的分辨率:

      import numpy as np
      
      for p in range(-5,5):
           pp = 10**p
           print("{:6g}: {}".format(pp, np.spacing(pp)))
      

      给予:

       1e-05: 1.69406589451e-21
      0.0001: 1.35525271561e-20
       0.001: 2.16840434497e-19
        0.01: 1.73472347598e-18
         0.1: 1.38777878078e-17
           1: 2.22044604925e-16
          10: 1.7763568394e-15
         100: 1.42108547152e-14
        1000: 1.13686837722e-13
       10000: 1.81898940355e-12
      

      这意味着例如1 + 2.22044604925e-16 == 1False10 + 2.22044604925e-16 == 10True。正如@OldGeeksGuide 指出的那样,您需要根据大小进行近似比较。另请参阅 Numpy 的 allclose() 以获得适当的比较

      【讨论】:

        猜你喜欢
        • 2011-02-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-01
        • 1970-01-01
        • 2012-12-06
        • 1970-01-01
        • 2011-10-21
        相关资源
        最近更新 更多