如何将信号NaN转换为安静的NaN?

时间:2011-11-18 10:09:23

标签: c floating-point nan

我想将信号NaN转换为C中的安静NaN。有人建议使用方法吗?

感谢。

2 个答案:

答案 0 :(得分:4)

我想我会扩展我的评论并提供解决方案。

这里棘手的部分是能够在不触发异常的情况下读取/比较sNaN。毕竟它被称为“信号”是有原因的。 Wikipedia says that even comparison operations on sNaN will trigger an exception.

因此,直接使用number != numberisnan(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和整数单元之间移动数据,因此这种方法效率不高。

以下是其工作原理:

  1. 联盟显然用于将float的位变为int
  2. 所有NaNs都会包含0x7f80000集中的位。 if语句测试将检查是否所有这些位都已设置。
  3. i |= 0x00400000;强制NaN安静NaN。位22确定NaN是静音还是静音。强制它为1会使它变得安静NaN

  4. 编辑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()

    请参阅此问题:Where is the source code for 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浮点语义。