带有效负载的双倍字面NaN

问题描述 投票:2回答:3

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

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

  • 双打的十六进制表示法(最好的选择,见here),但似乎只支持 有限值而不是无穷大或NaN 非NaN值(我可以通过使用infp1024获得p-1024s,但在这种情况下忽略尾数)
  • memcpy很好,因为它避免了别名但需要函数调用
  • reinterpret_cast只是C ++(可以)但是要求操作数是变量或指针而不是文字
  • union-type-punning但我认为这不能用于初始化静态时间常量

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

c double nan literals ieee-754
3个回答
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 char数组和一个double。我们初始化文字的数组字段并读取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
投票
  • memcpy不需要通过函数调用来实现。一个好的编译器会内联它并以其他方式优化它。
  • 可以初始化具有静态存储持续时间的常量联合对象。

1
投票

一种可能性是GCC(非便携式)__builtin_nan扩展,它可用于产生有效载荷的编译时NaN常量。

参考其文件:

如果给定一个字符串文字,所有这些函数都将由strtol使用,则该函数会被足够早地评估,以便将其视为编译时常量。

例:

#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
© www.soinside.com 2019 - 2024. All rights reserved.