是否存在isnan()函数?
注:我在MinGW(如果这有区别的话)。
我使用isnan()从<math.h>解决了这个问题,这在<cmath>中不存在,我一开始是#包括在内的。
是否存在isnan()函数?
注:我在MinGW(如果这有区别的话)。
我使用isnan()从<math.h>解决了这个问题,这在<cmath>中不存在,我一开始是#包括在内的。
当前回答
Boost中还提供了一个仅头文件的库,该库具有处理浮点数据类型的简洁工具
#include <boost/math/special_functions/fpclassify.hpp>
你会得到以下函数:
template <class T> bool isfinite(T z);
template <class T> bool isinf(T t);
template <class T> bool isnan(T t);
template <class T> bool isnormal(T t);
如果你有时间,那么看看Boost的整个数学工具包,它有许多有用的工具,并且正在快速增长。
此外,当处理浮点和非浮点时,查看数字转换可能是一个好主意。
其他回答
如果你的编译器支持c99扩展,有一个std::isnan,但我不确定mingw是否支持。
下面是一个小函数,如果你的编译器没有标准函数,它应该可以工作:
bool custom_isnan(double var)
{
volatile double d = var;
return d != d;
}
Boost中还提供了一个仅头文件的库,该库具有处理浮点数据类型的简洁工具
#include <boost/math/special_functions/fpclassify.hpp>
你会得到以下函数:
template <class T> bool isfinite(T z);
template <class T> bool isinf(T t);
template <class T> bool isnan(T t);
template <class T> bool isnormal(T t);
如果你有时间,那么看看Boost的整个数学工具包,它有许多有用的工具,并且正在快速增长。
此外,当处理浮点和非浮点时,查看数字转换可能是一个好主意。
在x86-64上,您可以使用非常快速的方法来检查NaN和无穷大,不管- fast-math编译器选项如何,这些方法都可以正常工作。(f != f, std::isnan, std::isinf使用- fast-math总是产生false)。
NaN、无穷大和有限数的测试可以通过检查最大指数轻松完成。无穷大是最大指数和零尾数,NaN是最大指数和非零尾数。指数存储在最上面的符号位之后的下一位,这样我们就可以左移来去掉符号位,让指数成为最上面的位,不需要屏蔽(操作符&):
static inline uint64_t load_ieee754_rep(double a) {
uint64_t r;
static_assert(sizeof r == sizeof a, "Unexpected sizes.");
std::memcpy(&r, &a, sizeof a); // Generates movq instruction.
return r;
}
static inline uint32_t load_ieee754_rep(float a) {
uint32_t r;
static_assert(sizeof r == sizeof a, "Unexpected sizes.");
std::memcpy(&r, &a, sizeof a); // Generates movd instruction.
return r;
}
constexpr uint64_t inf_double_shl1 = UINT64_C(0xffe0000000000000);
constexpr uint32_t inf_float_shl1 = UINT32_C(0xff000000);
// The shift left removes the sign bit. The exponent moves into the topmost bits,
// so that plain unsigned comparison is enough.
static inline bool isnan2(double a) { return load_ieee754_rep(a) << 1 > inf_double_shl1; }
static inline bool isinf2(double a) { return load_ieee754_rep(a) << 1 == inf_double_shl1; }
static inline bool isfinite2(double a) { return load_ieee754_rep(a) << 1 < inf_double_shl1; }
static inline bool isnan2(float a) { return load_ieee754_rep(a) << 1 > inf_float_shl1; }
static inline bool isinf2(float a) { return load_ieee754_rep(a) << 1 == inf_float_shl1; }
static inline bool isfinite2(float a) { return load_ieee754_rep(a) << 1 < inf_float_shl1; }
isinf和isfinite的std版本从.data段加载2个double/float常量,在最坏的情况下,它们会导致2个数据缓存失败。上面的版本不加载任何数据,inf_double_shl1和inf_float_shl1常量被编码为立即操作数进入程序集指令。
更快的isnan2只是2个组装指令:
bool isnan2(double a) {
bool r;
asm(".intel_syntax noprefix"
"\n\t ucomisd %1, %1"
"\n\t setp %b0"
"\n\t .att_syntax prefix"
: "=g" (r)
: "x" (a)
: "cc"
);
return r;
}
如果任何参数为NaN,则使用ucomisd指令设置奇偶校验标志的事实。这就是在没有指定- fast-math选项时std::isnan的工作方式。
考虑到(x != x)对于NaN并不总是保证的(比如如果使用- fast-math选项),我一直在使用:
#define IS_NAN(x) (((x) < 0) == ((x) >= 0))
数字不能同时< 0和>= 0,所以实际上只有当数字既不小于也不大于或等于0时,这个检查才会通过。基本上没有数字,或者NaN。
如果你喜欢,你也可以使用这个:
#define IS_NAN(x) (!((x)<0) && !((x)>=0)
我不确定这是如何受到快速数学的影响,所以你的里程可能会有所不同。
这可以在Visual Studio中通过检查它是否在双重限制范围内来检测无穷大和NaN:
//#include <float.h>
double x, y = -1.1; x = sqrt(y);
if (x >= DBL_MIN && x <= DBL_MAX )
cout << "DETECTOR-2 of errors FAILS" << endl;
else
cout << "DETECTOR-2 of errors OK" << endl;