提问人:shadowtalker 提问时间:2/14/2023 最后编辑:shadowtalker 更新时间:2/16/2023 访问量:109
关于比较浮点数的公差和公式的原则性推理?
Principled reasoning about tolerances and formulas for comparing floating-point numbers?
问:
Python 标准库包含函数 math.isclose
,它等效于:
abs(a - b) <= max(rtol * max(abs(a), abs(b)), atol)
Numpy 库同样包含 numpy.isclose 和 numpy.allclose
,它们等效于:
abs(a - b) <= (atol + rtol * abs(b))
这两个文档页面都没有解释为什么您希望使用其中一个公式而不是另一个公式,也没有提供任何选择合理的绝对公差和相对公差的原则标准,分别写在上面。atol
rtol
我经常不得不在代码测试中使用这些函数,但我从未学到在这两个公式之间进行选择或选择可能适合我的用例的容差的任何原则基础。
我通常只是保持默认值不变,除非我碰巧知道我正在做一些可能导致数值精度损失的事情,此时我会手动调整公差,直到结果看起来正确,主要基于直觉和手动检查示例。这是乏味的、不完美的,并且似乎与软件测试的目的背道而驰,尤其是基于属性的测试。
例如,我可能想断言同一算法的两个不同实现会产生“相同”的结果,并承认精确的相等性比较没有意义。
我可以使用哪些原则性技术来选择合理的公式和公差来比较浮点数?为了这个问题,我很高兴专注于测试使用浮点数的代码的情况。
答:
例如,我可能想断言同一算法的两个不同实现会产生“相同”的结果,并承认精确的相等性比较没有意义。
不要考虑对“相同”结果进行单一的真/假评估,而是尝试对算法在各种属性上的相同性进行评分。
如果评估在您的容差/限制范围内,则功能是“相同的”。
给定 和 (引用函数)。g(x)
r(x)
绝对差异:尝试各种(如果不是全部)。最大的是什么?
y = abs(g(x) - r(x))
x
y
相对差:尝试各种正态(非零)。最大的是什么?
y = abs((g(x) - r(x))/r(x))
r(x)
y
相对差异:如上所述,结果低于正常水平。这里的相对差异可能比正常值大得多,因此需要单独处理。 值得特别评估。
r(x)
r(x) == +/-0.0
范围测试/边缘情况:什么是最大/最小最大/最不“有效”。例如 并且可能在不同的位置返回无穷大或 0.0,但在其他方面几乎是“相同”。
x
y = my_exp(x)
exp(x)
x
总订购差异:(收藏)。使用名为 的辅助函数将所有非 NAN 浮点值 -inf 到 +inf 映射到整数:[-ORDER_N to ORDER_N] 是 0。找到最大差异并使用该指标来确定“相同”度。
total order()
total order(+/-0.0)
abs(total_order(g(x)) - total_order(r(x)))
各种功能值得特殊处理。该研究领域还有许多进一步的考虑。
使用相对公差时的一个问题是 - 相对于什么?如果你想知道 90 和 100 是否“相等”,公差为 10%,如果你取 90 的 10% 和 100 的 10%,你会得到不同的答案。
在该方案中定义“什么”时,标准库使用较大的 或,因此它将使用 100 的 10% 作为容差。它还使用相对公差或绝对公差中的较大者作为“最终”公差。a
b
numpy 方法简单地用于“相对”公差,并将相对公差和绝对公差的总和作为“最终”公差。b
哪个更好?两者都没有好坏之分——它们是建立宽容的不同方式。您可以根据要如何定义“足够接近”来选择要使用哪一个。
您选择的公差也与上下文相关 - 您是在比较木材的长度还是微处理器中电路路径之间的距离?1%的公差是“足够好”还是需要超精密公差?容差过低可能会产生过多的“误报”,具体取决于应用程序,而过高的容差会产生过多的“漏报”,这可能会让一些问题“从裂缝中溜走”。
请注意,标准函数不是矢量化的,所以如果你想在数组上使用它,你要么必须使用 numpy 函数,要么构建标准函数的垂直化版本。
没有人可以为您选择公差,它们取决于问题。因为在现实生活中,您处理的输入数据的精度(非常)有限,无论是实验测量的结果还是引入截断误差的数值计算的结果。因此,您需要了解您的数据并了解误差演算的概念和方法才能对其进行调整。
至于公式,它们被设计为通用的,即不知道要比较的量是否可以严格相等(当它们严格相等时,相对误差不起作用)。同样,这不应该是一个盲目的选择。
评论
math.isclose
numpy.isclose
numpy.allclose