如何手动设置等于NaN的float的位值?

时间:2012-04-28 16:19:45

标签: c floating-point nan

我正在尝试使用转换和浮点数转换为其他类型运行一些测试,我想将我的浮点变量设置为不同的nan值。

“IEEE浮点标准单精度(32位)NaN的一个逐步示例是:s111 1111 1axx xxxx xxxx xxxx xxxx xxxx其中s是符号(在应用程序中最常被忽略),a确定NaN的类型,x是一个额外的有效载荷(通常在应用程序中被忽略)。如果a = 1,它是一个安静的NaN;如果a是零且有效载荷是非零的,那么它是一个信令NaN“

基本上我想找到一种方法来设置表示的有效载荷或xxxx。有没有办法在c中做到这一点?

3 个答案:

答案 0 :(得分:8)

您可以通过将适当的字符串传递给C99 nan, nanf, nanl函数来控制“有效负载”位,但这些只会生成 quiet NaN,并且字符串的解释是未指定(大多数实现将其视为十六进制数)。

或者,使用union:

#ifndef __STDC_IEC_559__
#error "This program requires IEEE floating point arithmetic"
#endif

#include <stdint.h>
#include <assert.h>

static_assert(sizeof(float) == sizeof(uint32_t),
    "This program requires float to be 32 bits exactly");

float nanf_with_payload_bits(uint32_t payload)
{
   if (payload & 0x7FA00000) abort();

   union ieee_single {
       float f;
       uint32_t i;
   } nan;

   nan.i = 0x7FA00000 | payload;
   return nan.f;
}

写入联合的一个成员然后从另一个成员读取,当两个类型的大小完全相同时,不会在C99 +勘误表中引发未定义的行为。 (在C89中是未定义的行为,但是大多数编译器将它定义为你所期望的。它可能仍然是C ++中未定义的行为,我不确定;但是,大多数编译器再次定义它做你期望的事。)

如果您使用此功能创建信令 NaN,请注意它们的行为在C99 / C11附件F中明确未定义。

请勿尝试将联合的i组件分解为具有位字段的结构。结构中位字段的存储器布局部分是实现定义的并且部分未指定,特别是一系列位字段必须以与CPU字节顺序相同的顺序打包到字中。 (或者,实际上,根本没有妥善包装)。


标准引用(所有C99):

  • 对union的使用只是未指定的行为:6.2.6.1p7; J.1
  • 结构中位域的布局是不可预测的:6.2.6.1p1,2; 6.7.2.1p10,11,13; J.3.9
  • 信号NaN的行为未定义:F.2.1

答案 1 :(得分:3)

使用memcpy

int32_t i = 0x7FC00000;
float f;
memcpy(&f, &i, sizeof(f));

你也可以声明sizeof(f) == sizeof(i),但如果你知道浮点数是IEEE,那么你可能也知道基本类型的大小。

答案 2 :(得分:3)

支持在C中写入安静NaN的有效负载的方法。

nan,nanf和nanl函数(math.h标题,1999 C规范的7.12.11.2节)接受字符串作为参数。 strtof,strtod和strtold函数(stdlib.h头文件,第7.20.1.3节)接受“NAN(字符序列)”形式的字符串。 fscanf和sscanf函数遵循strtod。但是,字符序列以实现定义的方式解释。 (这意味着您的编译器应该为您提供指定解释的文档。某些编译器将不遵守标准的此要求。)

fprintf函数(stdio.h,第7.19.6.1节)可以输出带有浮点格式(a,e,f,g)的“NAN(字符序列)”形式的字符串,如printf和sprintf的。该标准允许输出“NAN”而没有字符序列,因此这对许多编译器都不起作用。

由于解释是实现定义的,因此您不应期望它们是可移植的。它们通常用于特殊目的,例如调试。