从 float 到 double 的 NaN 转换会更改其基础数据

NaN conversion from float to double changes its underlying data

提问人:Dan 提问时间:4/7/2022 更新时间:4/7/2022 访问量:209

问:

int main(){

  unsigned int a = 2139156962;
  float b = *(float*)&a;       // nan(0xf1e2)
  double c = (double)b;        // nan canonicalization? 
  float d = (float)c;          // nan(0x40f1e2), d != b
  unsigned int e = *(int*)&d;  // e != a

  return 0;
}

NaN 值可以用许多不同的方式表示。如上例所示,将 的 NaN 值转换为 double 类型不会保留输入位模式,将其转换回浮点数不会返回与原始输入相同的值。nan(0xf1e2)

这个链接中,我可以在 x64 上看到,似乎规范了 Qnan 输入?CVTSS2SD

符号位被保留,8 位指数 FFH 被 11 位指数 7FFH 取代,24 位有效数通过附加等于 0 的 29 位扩展到 53 位有效数。

因此,无论我们输入的 Qnan 位模式是什么,输出都会使用并且不会保留所有原始位?这是某种 NaN 规范化吗?0x7FF

如果是这样,那么这个答案可能并不完全准确?

浮点数可以提升为双倍,并且值保持不变。

我们的输出仍然是 NaN,但基础数据现在已更改,并且 .c != b

C 铸造 浮点 NAN

评论

4赞 Eugene Sh. 4/7/2022
你在这里调用了一堆 UB......
2赞 njuffa 4/7/2022
这从 SNaN(信号 NaN)模式开始。当浮点异常被解除屏蔽时,对 SNaN 进行操作将发出异常信号。当异常被屏蔽时,SNaN 将转换为相应的 QNaN(安静 NaN),方法是将存储有效值的最高有效位强制为 1。对于 x86 硬件上的 IEEE-754,这相当于 OR-ing 进入位模式。这里:binary320x00400000a=7f80f1e2 b=7f80f1e2 c=7ff81e3c40000000 d=7fc0f1e2 e=7fc0f1e2
1赞 njuffa 4/7/2022
请注意,NaN“有效载荷”是 IEEE-754 标准的可选功能,即“应该”条款,而不是“应”条款。
1赞 njuffa 4/7/2022
@Dan Andrew Shell Waterman,“RISC-V 指令集架构的设计”,博士论文,加州大学伯克利分校,2016 年提供了有用的概述。特别是:“表 4.4:多个 ISA 的默认单精度 NaN。QNaN 极性是指有效位的最高有效位是否表示 NaN 在设置时是安静的,还是在清除时是安静的。“ 您说得对,QNaN/SNaN 区分位在 2008 版的 IEEE-754 标准中得到了澄清(但是,该标准没有改变现有硬件)。
1赞 Wisblade 4/7/2022
@Dan 想一想:例如,当你将0x1456abd83贬低到一个字符时......会发生什么?二进制截断?溢出?例外?别的?你不可能知道,它可能因平台而异。这就是为什么它是UB的原因:规范并不能保证在所有可能的平台上都有已知的结果。查看 C99 标准,§6.3。对于浮点数,它说“如果转换的值超出了可以表示的值范围,则行为未定义。而 NaN 就是这样一个值。另请参见关于 NaN 的 §7.12.3.4。

答: 暂无答案