我想在我的构建选项中启用 -Wfloat-equal (这是一个 GCC 标志,当通过 == 或 != 运算符比较两个浮点指针数字时会发出警告)。然而,在我使用的库的几个头文件以及我自己的代码的很大一部分中,我经常想使用
if (x)
或 if (x != 0)
或它们的变体来分支为 float 或 double 的非零值。
因为在这些情况下,我绝对确定该值恰好为零 - 检查的值是显式零初始化的结果,
calloc
等 - 我看不出使用这种比较的缺点,而不是更多对我的 near(x, 0)
函数的调用昂贵且可读性较差。
是否有某种方法可以为所有其他类型的浮点相等比较获得
-Wfloat-equal
的效果,但允许这些不带标记地通过?库头文件中有足够多的实例,它们可能会严重污染我的警告输出。
从你问的问题来看,这个警告似乎是完全恰当的。如果您与精确的零进行比较来测试数据是否仍然具有来自
calloc
的初始零值(从纯 C 的角度来看,这实际上是不正确的,但适用于任何符合 IEEE 754 的实现),您可能会从以下位置得到误报:非零值已四舍五入为零。换句话说,听起来您的代码不正确。
这非常可怕,但这避免了警告:
#include <functional>
template <class T>
inline bool is_zero(T v)
{
return std::equal_to<T>()(v, 0);
}
GCC 不会报告系统标头的警告,这会导致相等测试发生在系统标头内。
可以使用
std::fpclassify
函数来检查值是否为零(正数或负数)。
例如:
#include <iostream>
#include <cmath>
#include <cstdlib>
bool is_zero (float x)
{
return std::fpclassify (x) == FP_ZERO;
}
int main (int, char **)
{
float a {-0.f};
float b {+1.f};
std::cout << is_zero (a) << std::endl;
std::cout << is_zero (b) << std::endl;
return EXIT_SUCCESS;
}
构建:
g++ main.cpp -o main -std=c++17 -Wall -Wextra -Wfloat-equal -Wfloat-conversion -Wdouble-promotion
运行:
1
0