我想我会扩展我的评论并提供解决方案。
这里棘手的部分是能够读取/比较sNaN
而不触发异常。毕竟,它被称为“信号”是有原因的。维基百科说,即使是比较操作sNaN会触发异常。
所以直接使用number != number
or isnan(value)
可能不起作用,因为它们调用比较并会触发硬件异常。 (我不完全确定如何isnan(value)
虽然已实施。)
EDIT :更正一下,看起来像isnan()
即使在信令上也永远不会触发异常NaN
所以这使得这个答案的其余部分毫无意义。
谓词 isNaN(x) 确定一个值是否为 NaN,并且从不
即使 x 是一个信号 NaN,也会发出异常信号。
这意味着它可以按照 Chrisoph 在评论中的建议来完成:
if(isnan(value))
value = NAN;
这是我原来的答案,不使用isnan(value)
:
所以我能想到的唯一方法就是采用按位路线。
假设float
是标准 IEEE 单精度并且int
是一个 32 位整数,那么这是一种解决方法:(请注意,我还没有测试过这一点。)
union{
int i;
float f;
} val;
val.f = // Read the value here.
// If NaN, force it to a quiet NaN.
if ((val.i & 0x7f800000) == 0x7f800000){
val.i |= 0x00400000;
}
请注意,此方法并不完全符合 C 语言,并且将调用实现定义的行为。另请注意,由于需要在 FP 和整数单元之间移动数据,这种方法并不是特别有效。
这是它的工作原理:
- 联合显然是用来获取
float
进入一个int
.
- All
NaNs
将有位0x7f80000
放。 if 语句测试将检查是否所有这些位都已设置。
-
i |= 0x00400000;
迫使NaN
到一个安静的NaN
。位 22 决定是否NaN
是沉默的或安静的。强制它为 1 会使其安静NaN
.
EDIT 2:如果您不能使用联合,这里有一些其他方法(每种方法都有自己的缺点):
方法一:
float f = // Read the value here.
int i = *(int*)&f;
if ((i & 0x7f800000) == 0x7f800000){
i |= 0x00400000;
}
f = *(float*)&i;
缺点:它违反了严格的别名,但可能仍然有效。
方法二:
char buf[sizeof(float)];
float f = // Read the value here.
*(float*)&buf = f;
int i = *(int*)&buf;
if ((i & 0x7f800000) == 0x7f800000){
i |= 0x00400000;
}
*(int*)&buf = i;
f = *(float*)&buf;
同样的想法适用于memcpy()
.
缺点:如果对齐很重要,您需要确保buf
已对齐。
方法三:实施你自己的isnan()
:
看这个问题:isnan 的源代码在哪里?