有 isnan() 函数吗?
PS.:我在 MinGW (如果这有什么不同的话)。
我通过使用 <math.h>
中的 isnan() 解决了这个问题,这在 <cmath>
中不存在,我是 #include
首先。
原文由 hasen 发布,翻译遵循 CC BY-SA 4.0 许可协议
在 x86-64 上,您可以使用非常快速的方法来检查 NaN 和无穷大,无论 -ffast-math
编译器选项如何,这些方法都可以工作。 ( f != f
, std::isnan
, std::isinf
always yield false
with -ffast-math
).
通过检查最大指数可以很容易地测试 NaN、无穷大和有限数。无穷大是尾数为零的最大指数,NaN 是最大指数和非零尾数。指数存储在最高符号位之后的下一位中,因此我们只需左移即可摆脱符号位并使指数成为最高位,无需屏蔽( operator&
):
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; }
The std
versions of isinf
and isfinite
load 2 double/float
constants from .data
segment and in the worst case scenario它们可能导致 2 次数据缓存未命中。上述版本不加载任何数据, inf_double_shl1
和 inf_float_shl1
常量被编码为立即操作数到汇编指令中。
Faster isnan2
只是两条汇编指令:
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
指令设置奇偶校验标志这一事实。当没有指定 -ffast-math
选项时,这就是 std::isnan
的工作方式。
原文由 Maxim Egorushkin 发布,翻译遵循 CC BY-SA 4.0 许可协议
3 回答2k 阅读✓ 已解决
2 回答3.9k 阅读✓ 已解决
2 回答3.2k 阅读✓ 已解决
1 回答3.2k 阅读✓ 已解决
1 回答2.7k 阅读✓ 已解决
3 回答3.4k 阅读
1 回答1.6k 阅读✓ 已解决
根据 IEEE 标准,NaN 值具有奇数特性,即涉及它们的比较 总是 错误的。也就是说,对于浮点数 f, 只有 当 f 为 NaN 时,
f != f
才会为真。请注意,正如下面的一些评论所指出的,并非所有编译器在优化代码时都尊重这一点。
对于任何声称使用 IEEE 浮点的编译器,这个技巧 应该可以 工作。但我不能保证它 会 在实践中发挥作用。如果有疑问,请检查您的编译器。