4

NaN我对 IEEE 单精度和双精度浮点的实现和表示感到好奇,我发现了“is NaN”函数的这种实现。即:

int isnan(double x)
{
    int32_t hx,lx;

    // Move lower 32 bits of double to lx, higher 32 to hx.
    EXTRACT_WORDS(hx,lx,x);

    // Remove sign bit, since -NaN and NaN are both NaN.
    hx &= 0x7fffffff;

    // Equivalent to hx |= (lx != 0).
    hx |= (u_int32_t)(lx|(-lx))>>31;

    // Difference is negative iff (hx & 0x7ff00000) == 0x7ff00000 and (hx & 0x000fffff) != 0.
    hx = 0x7ff00000 - hx;
    return (int)((u_int32_t)(hx))>>31;
}

我不明白 的目的(lx|(-lx)) >> 31,并且在我的头脑中没有推理出来之后,我对所有整数进行了测试,发现结果为 0 ,lx = 0否则为 1。

我能想出的唯一原因是,(lx != 0)由于某些 C 标准没有定义为真操作分配什么整数值(例如,不保证为真时为 1),或者可能!=比负数慢,所以可能无法使用代替 -或位移位。否则,我难住了。

作为参考,我用来尝试所有整数的代码,以防出错。

#include <stdio.h>
#include <stdint.h>
int main(void) {
        int32_t i = 0;
        do {
                if (((uint32_t)(i | (-i)) >> 31) == 0)
                        printf("%d\n", i); // prints only 0
        } while (i++ != 0xFFFFFFFF); // overflows to -max_int and then climb to -1
        return 0;
}
4

1 回答 1

3

表达式(u_int32_t)(lx|(-lx))>>31等价于lx==0? 0:1

但是,使用lx==0? 0:1,您将分支操作强加到目标代码中。

与几个按位操作相比,这可能会降低性能。

这实际上取决于底层硬件架构以及手头指定的编译器。

但它肯定会导致性能不一致,具体取决于分支预测启发式。

(u_int32_t)(lx|(-lx))>>31保证每次执行的运行时间都是相同的。

于 2014-09-18T07:12:29.777 回答