Python新手如何克服浮点比较的问题

时间:2014-04-01 21:08:59

标签: python floating-point

对于一个很长的问题很抱歉,对于那些并非真正极少的代码。

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

但是,我不知道如何应用响应,例如“为什么你不使用str(值)”或“只是用%格式化”或“你必须使用十进制”。我最喜欢的主题是“忽略第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]

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

我不是在做财务会计,也不需要很多很多有价值的数据。

对于此代码,您如何建议我继续我的初学者教育?

2 个答案:

答案 0 :(得分:6)

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

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

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

答案 1 :(得分:0)

了解浮点并不困难。要记住两件事: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()进行适当的比较