比较浮点数 - Google Test Framework

时间:2013-09-06 21:14:57

标签: c++ floating-point floating-accuracy

用户@skrebbel在SO上发表this帖子时表示谷歌测试框架在比较浮动和双打方面做得很好而且快速。所以我编写了下面的代码来检查代码的有效性,显然我似乎在这里遗漏了一些东西,因为我希望在这里输入几乎相等的部分这是我的代码

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 ?
}

任何建议都会受到赞赏。

3 个答案:

答案 0 :(得分:8)

您的leftright并非“几乎相等”,因为它们相距太远,远远超过AlmostEquals的默认容差。您链接的问题中的一个答案中的代码显示容差为4 ULP,但您的数字相差14 ULP(使用IEEE 754 32位二进制和正确舍入软件)。 (ULP是浮点值的最小增量。对于小幅度的浮点数而言,它是小的,对于大数字,它是大的,因此它大约相对于数字的大小。)

如果不了解您所比较的值中的错误以及您正在执行的比较,则不应执行任何浮点比较。

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

通常人们会尝试通过接受略有不同的相同数字来解决其浮点值中的错误。这减少了假阴性(由于先前的计算错误导致的不平等的指示),代价是增加误报(由不接受引起的平等的指示)。这种错误与另一种错误的交换是否可接受取决于应用程序。没有通用的解决方案,这就是像AlmostEquals这样的函数通常不好的原因。

浮点值中的错误是前面操作和值的结果。这些误差的范围可以从零到无穷大,具体取决于具体情况。因此,不应该只接受AlmostEquals等函数的默认容差。相反,应该计算容差,该容差特定于其应用,需求和计算,并使用该计算的容差(或者根本不使用比较)。

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

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

答案 1 :(得分:7)

您可以使用

ASSERT_NEAR(val1, val2, abs_error); 

你可以给予可接受的 - 你所选择的,例如0.0000001 - 差异为abs_error,如果默认值太小,请参阅此处https://github.com/google/googletest/blob/master/googletest/docs/advanced.md#floating-point-comparison

答案 2 :(得分:0)

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

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

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