带有效负载的双倍文字NaN

时间:2017-12-20 17:24:24

标签: c double nan literals ieee-754

我正在使用带有效负载的NaN(因此尾数包含重要信息,但仍被视为NaN)。例如,一个这样的值可以使用十六进制的IEEE-754-1985表示为FFF8000055550001,其符号位为1,NaN /无穷大的指数为7FF,安静的NaN位集(至少在大多数架构上),以及0x55550001的有效载荷。

然而,这有一些问题。首先,这不能像C / C ++中的文字那样容易地创建,因为常用方法都不能用于初始化文字:

  • hex-literal表示双精度(最佳选项,见here)但似乎只支持有限值而不是无穷大或NaNs 非NaN值(我可以得到{{ 1}}使用infp1024,但在这种情况下忽略尾数)
  • p-1024很好,因为它避免了别名但需要函数调用
  • memcpy仅限C ++(可以),但要求操作数是变量或指针而不是文字
  • union-type-punning但我不认为这可用于初始化静态时间常数

是否有任何方法可以为带有效负载的NaN设置静态常量?可以假设系统符合IEEE-754-1985并且reinterpret_castlong具有相同的字节序。

3 个答案:

答案 0 :(得分:2)

您可以使用复合文字执行此操作,然后您可以获取地址和演员:

double d = ((union {unsigned char c[8]; double d; }){ .c={1,0,0,0,0,0,0xf0,0x7f} }).d;
printf("d=%f\n", d);

int i;
printf("d=0x");
for (i=0; i<sizeof(double); i++) {
    unsigned char c = ((unsigned char *)&d)[sizeof(double)-1-i];
    printf("%02x", c);
}
printf("\n");

在这里,我们有一个匿名文字联合,其中包含一个大小为8 unsigned chardouble的数组。我们初始化文字的数组字段并读取double部分以初始化变量。

输出:

d=nan
d=7ff0000000000001

我们可以用宏来清理它,并且还要处理字节序:

static_assert(sizeof(double)==8, "unexpected double size");

#if __BYTE_ORDER == __BIG_ENDIAN
#  define DOUBLE_LIT(c1,c2,c3,c4,c5,c6,c7,c8) ((union {unsigned char c[8]; double d; }){ .c={c1,c2,c3,c4,c5,c6,c7,c8} }).d
#elif __BYTE_ORDER == __LITTLE_ENDIAN
#  define DOUBLE_LIT(c1,c2,c3,c4,c5,c6,c7,c8) ((union {unsigned char c[8]; double d; }){ .c={c8,c7,c6,c5,c4,c3,c2,c1} }).d
#else
#  error unknown endianness
#fi

然后我们可以像这样使用它:

double d = DOUBLE_LIT(0x7f,0xf0,0,0,0,0,0,1);

请注意,字节顺序检查取决于系统。以上是它通常在Linux上实现的方式。

答案 1 :(得分:1)

  • memcpy不需要通过函数调用来实现。一个好的编译器会内联并优化它。

  • 可以初始化具有静态存储持续时间的常量联合对象。

答案 2 :(得分:1)

一种可能性是GCC(非可移植)__builtin_nan扩展,可用于生成带有效负载的编译时NaN常量。

参考其文件:

  

这个函数,如果给出一个字符串文字,所有这些都是   由strtol消耗,被评估得足够早以至于被认为是a   编译时常量。

示例:

#include <stdio.h>

#define MAKE_QNAN_WITH_PAYLOAD(sign, payload) \
    sign __builtin_nan(#payload)

double d = MAKE_QNAN_WITH_PAYLOAD(-, 0x55550001);

int main(void)
{
    // assume little-endian byte ordering
    for (int i = sizeof(double)-1; i >= 0; i--)
    {
        printf("%.2x", ((unsigned char *)&d)[i]);
    }
    putchar('\n');

    return 0;
}

结果:

fff8000055550001