4

用户 @skrebbel 在 SO上浏览这篇文章时说,谷歌测试框架在比较浮点数和双精度数方面做得很好而且很快。所以我写了下面的代码来检查代码的有效性,显然我在这里遗漏了一些东西,因为我希望在这里输入几乎等于部分这是我的代码

float left = 0.1234567;
float right= 0.1234566;

const FloatingPoint<float> lhs(left), rhs(right);


if (lhs.AlmostEquals(rhs)) 
{
    std::cout << "EQUAL"; //Shouldnt it have entered here ?
}

任何建议将不胜感激。

4

3 回答 3

8

您的leftright不是“几乎相等”,因为它们相距太远,比 . 的默认容差更远AlmostEquals。您链接到的问题中的一个答案中的代码显示了 4 ULP 的容差,但您的数字相隔 14 ULP(使用 IEEE 754 32 位二进制和正确舍入软件)。(ULP是浮点值的最小增量。对于小幅度的浮点数来说它很小,对于大数来说它很大,因此它与数字的幅度大致相关。)

在不了解您正在比较的值中可能存在哪些错误以及您正在执行什么比较之前,您永远不应该执行任何浮点比较。

人们经常错误地说您不能测试浮点值是否相等。这是错误的;执行a == b是一个完美的操作。当且仅当a等于b(即,a并且b是具有完全相同值的数字)时,它才返回 true。实际问题是他们试图在输入不正确的情况下计算正确的函数。==是一个函数:它接受两个输入并返回一个值。显然,如果你给任何函数输入不正确,可能会返回不正确的结果。所以这里的问题不是浮点比较;这是不正确的输入。在输入错误的情况下,您通常无法正确计算总和、乘积、平方根、对数或任何其他函数。因此,在使用浮点数时,您必须设计一种算法来处理近似值(或者,在特殊情况下,要非常小心以确保不会引入错误)。

人们经常尝试通过接受略有不同的相等数字来解决浮点值中的错误。这减少了假阴性(由于先前的计算错误导致的不平等迹象),但代价是增加了假阳性(由于接受不严而导致的平等迹象)。这种用一种错误交换另一种错误是否可以接受取决于应用程序。没有通用的解决方案,这就是为什么像这样的功能AlmostEquals通常不好。

浮点值中的错误是先前操作和值的结果。根据具体情况,这些错误的范围可以从零到无穷大。因此,绝不应该简单地接受函数的默认容差,例如AlmostEquals. 相反,人们应该计算公差,这是特定于他们的应用、需求和计算的,并使用计算出的公差(或者根本不使用比较)。

AlmostEquals另一个问题是,经常使用相对于被比较的值指定的容差来编写诸如此类的函数。但是,值中的误差可能受到幅度差异很大的中间值的影响,因此最终误差可能是所比较的值中不存在的数据的函数。

在测试其他代码的代码中,“近似”浮点比较可能是可以接受的,因为大多数错误可能会导致大错误,因此对相等性的宽松接受将允许好的代码继续运行,但会在大多数坏代码中报告错误。但是,即使在这种情况下,您也必须适当地设置预期结果和允许的误差容限。该AlmostEquals代码似乎对容错进行了硬编码。

于 2013-09-06T21:37:14.590 回答
8

您可以使用

ASSERT_NEAR(val1, val2, abs_error); 

您可以在其中给出可接受的值-您选择的值,例如 0.0000001-差异为abs_error,如果默认值太小,请参见此处https://github.com/google/googletest/blob/master/googletest/docs/advanced .md#浮点比较

于 2013-09-06T21:19:43.783 回答
2

(不确定这 100% 是否适用于原始问题,但这就是我偶然发现它时的目的)

如果您不想自己担心可容忍的错误,也可以使用和(或对应的 double 版本)ASSERT_FLOAT_EQEXPECT_FLOAT_EQ

文档:https ://github.com/google/googletest/blob/master/docs/reference/assertions.md#floating-point-comparison-floating-point

于 2021-06-29T14:27:25.243 回答