我想将信号NaN转换为C中的安静NaN。有人建议使用方法吗?
感谢。
答案 0 :(得分:4)
我想我会扩展我的评论并提供解决方案。
这里棘手的部分是能够在不触发异常的情况下读取/比较sNaN
。毕竟它被称为“信号”是有原因的。 Wikipedia says that even comparison operations on sNaN
will trigger an exception.
因此,直接使用number != number
或isnan(value)
可能不起作用,因为它们会调用比较并触发硬件异常。 (我不完全确定isnan(value)
是如何实现的。)
编辑:更正,看起来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
。NaNs
都会包含0x7f80000
集中的位。 if语句测试将检查是否所有这些位都已设置。i |= 0x00400000;
强制NaN
安静NaN
。位22确定NaN
是静音还是静音。强制它为1会使它变得安静NaN
。编辑2:如果您不能使用工会,这里有一些其他方法(每种方法都有自己的缺点):
方法1:
float f = // Read the value here.
int i = *(int*)&f;
if ((i & 0x7f800000) == 0x7f800000){
i |= 0x00400000;
}
f = *(float*)&i;
下行:它违反了严格的别名,但可能仍会有效。
方法2:
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
已对齐。
方法3:实施您自己的isnan()
:
答案 1 :(得分:1)
在评论中,你提到了你真正想做的事情:
在我执行任何其他操作之前,我想检查NaN,即数字!=数字,但这不适用于信号NaN
这就是C99 isnan()
宏的用途,不需要number != number
。 C标准本身并没有真正指定信令NaN的语义 - 它只是说
信令NaN 通常在作为算术操作数发生时引发浮点异常
在第5.2.4.2.2节§3和
中本规范未定义信令NaN的行为。
见附件F第F.2.1节§1。
但是,according to Wikipedia,IEEE 754指定 isNaN()谓词,即使与信令NaN一起使用也不会引发异常,isnan()
应该在实现时相应地表现它提供了IEEE浮点语义。