如何打印NaN的有效负载

How to print payload of a NaN?

本文关键字:NaN 有效 负载 打印 何打印      更新时间:2023-10-16

我们有像std::nanl这样的特殊函数来生成带有有效负载的NaN。目前,我要做的是打印回来:

#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdint>
int main()
{
    const auto x=std::nanl("1311768467463790325");
    std::uint64_t y;
    std::memcpy(&y,&x,sizeof y);
    std::cout << (y&~(3ull<<62)) << "n";
}

这取决于long double的特定表示,即它是x87 FPU的80位类型。有没有任何标准的方法可以在不依赖于这些实施细节的情况下实现这一点?

C++从ISO C导入nan*函数。ISO C在7.22.1.3中声明:

n字符序列的含义是实现定义的

带有注释

一种实现可以使用n-char序列来确定要在NaN的有效位中表示的额外信息。

没有获取存储信息的方法。

我在2023年偶然发现了这个。
情况没有太大改善

  • C11支持nan*()功能(如果目标处理器支持QNaN),但是
  • MSVC 2022实际上没有实现有效载荷编译
  • 有效负载必须指定为字符串,并且
  • 仍然没有获取数据的标准方法
  • (C23提出了GNU扩展getPayload(),但它返回了另一个double,这远没有整数那么有趣。)

然而

假设您有一个带有有效载荷数据的适当IEEE 754 QNaN,那么获得QNaN有效载荷一直是可能的。例如,它在执行JavascriptLua等操作的系统上得到了很好的使用[需要引文]

根据维基百科,在讨论了一些恐龙之后:[链接]

因此,广泛使用的IEEE 754浮点标准没有指定字节序,这可能显得很奇怪[3]从理论上讲,这意味着即使是一台机器编写的标准IEEE浮点数据也可能无法被另一台机器读取。然而,在现代标准计算机(即,实现IEEE 754)上,可以有把握地假设浮点数的字节序与整数的字节序相同,无论数据类型如何,转换都很简单。然而,使用特殊浮点格式的小型嵌入式系统可能是另一回事
强调

因此,只要你没有在内部使用之外泄露抽象,或者使用专门的(或古老的)硬件,那么你就应该善于在QNaN中填充东西。

由于这个问题被标记为C++,我们将不得不使用比C中严格需要的代码稍微丑陋的代码,因为在C++中,带有并集的类型双关语(可能)是UB[更多链接]以下内容应该在C和C++中都能工作,并且无论哪种方式都能产生同样优化的代码。

达或回家

qnan.h

#ifndef QNAN_H
#define QNAN_H
// Copyright stackoverflow.com
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  https://www.boost.org/LICENSE_1_0.txt )
#include <assert.h>
#include <math.h>
#include <stdint.h>
#ifndef NAN
  #error "IEEE 754 Quiet NaN is required."
#endif
#ifndef UINT64_MAX
  #error "uint64_t required."
#endif
static_assert( sizeof(double) == 8, "IEEE 754 64-bit double-precision is required" );
double             qnan         ( unsigned long long payload );
unsigned long long qnan_payload ( double             qnan    );
#endif

qnan.c

// Copyright stackoverflow.com
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  https://www.boost.org/LICENSE_1_0.txt )
#include <string.h>
#include "qnan.h"
double 
qnan( unsigned long long payload )
{
  double qnan = NAN;
  uint64_t n;
  memcpy( &n, &qnan, 8 );
  n |= payload & 0x7FFFFFFFFFFFFULL;
  memcpy( &qnan, &n, 8 );
  return qnan;
}
unsigned long long 
qnan_payload( double qnan )
{
  uint64_t n;
  memcpy( &n, &qnan, 8 );
  return n & 0x7FFFFFFFFFFFFULL;
}

这两个函数允许您访问作为无符号整数的所有51位有效负载数据。

然而,请注意,与奇怪的o getPayload()函数不同,qnan_payload()函数并不麻烦对您的输入选择进行事实核查——它假设您已经给了它一个实际的QNaN。

如果你不确定你有什么类型的double<math.h>中的isnan()函数可以很好地检查QNaNess。

类似的代码将允许您访问四字节float或N字节long double(这可能只是一个8字节double,除非它不是,而且可能更难支持)。