Catch2使用相对误差校验0.0浮点数结果失败问题排查
Catch2校验boost四元数R_component_1()相对误差失败的原因
核心问题
当用相对误差校验接近0的浮点值时,逻辑本身存在缺陷,这是R_component_1()校验失败的根本原因;而R_component_4()能通过,是因为它的实际值非零,相对误差计算有效。
具体拆解
相对误差在0值附近的失效
相对误差的计算公式为:|实际值-基准值| / max(|实际值|, |基准值|)。如果基准值是0.0,分母就变成了|实际值|——假设你的R_component_1()计算结果是1e-8(一个接近0的小值),此时相对误差会是1e-8 / 1e-8 = 100%,直接超出你设置的0.01%阈值,自然失败。
Catch2的Approx在基准值为0时会自动切换到绝对误差校验,但默认的绝对误差阈值是机器epsilon级(约1e-16),远小于实际计算误差,所以还是过不了。报错"对比0.0与整数0"的由来
你最初的校验代码大概率写的是Approx(0)(整数0)而非Approx(0.0)(浮点数),比如:REQUIRE(quat.R_component_1() == Approx(0));这时
Approx用int类型的0做基准,和double类型的返回值对比,触发了隐式类型转换,Catch2的错误信息就会显示两个类型不同的0,同时进一步干扰了误差计算逻辑。R_component_4()通过的原因
因为R_component_4()的实际结果是非零的(比如接近1.0),这时候相对误差计算完全正常:假设实际值是1.000001,基准值是1.0,相对误差仅为0.0001%,远低于你允许的0.01%,所以轻松通过。
正确的校验方式
- 针对接近0的浮点值,必须用绝对误差:
// 用Approx指定绝对误差margin(0.01%的相对误差对应0值的绝对误差可设为1e-4,根据计算精度调整) REQUIRE(quat.R_component_1() == Approx(0.0).margin(1e-4)); // 或者直接用WithinAbs更直观 REQUIRE(quat.R_component_1() == Catch::WithinAbs(0.0, 1e-4)); - 非零浮点值可以继续用相对误差:
// epsilon设为0.0001对应0.01%的相对误差 REQUIRE(quat.R_component_4() == Approx(expected_4_val).epsilon(0.0001));
内容的提问来源于stack exchange,提问作者Chris F
相关产品推荐
相关产品推荐

