假设使用C中的IEEE754浮点表示浮点数是否安全?

浮点是在C中定义的实现。因此没有任何保证。

我们的代码需要是可移植的,我们正在讨论在我们的协议中使用IEEE754浮点数是否可以接受。 出于性能原因,如果我们不必在发送或接收数据时在固定点格式之间来回转换,那将是很好的。

虽然我知道平台和架构之间可能存在关于longwchar_t大小的差异。 但我似乎无法找到任何关于floatdouble具体信息。

到目前为止,我发现字节顺序可能在大端平台上反转。 虽然有没有浮点支持的平台,其中包含floatdouble的代码甚至不会链接。 否则平台似乎坚持IEEE754单精度和双精度。

因此可以安全地假设浮点在IEEE754可用时?

编辑:回应评论:

你对“安全”的定义是什么?

安全我的意思是,一个系统上的位模式在另一个系统上意味着相同(在字节旋转之后处理字节序)。

基本上所有当前非穿卡使用的架构,包括嵌入式架构和外来信号处理架构,都提供了两个浮点系统之一:

  • IEEE-754。
  • IEEE-754 除了等等 。 也就是说,他们大多实现754,但在一些更昂贵和/或繁琐的位上便宜。

最常见的廉价出口:

  • 将非正规数刷新为零。 这使某些有时有用的定理无效(特别是,如果0 <= a/2 <= b <= a*2ab可以精确表示的定理),但实际上它通常不会成为问题。
  • 未能识别infNaN特殊。 这些体系结构将无法遵循关于infNaN作为操作数的规则,并且可能不会饱和到inf ,而是产生大于FLT_MAX ,其通常被其他体系结构识别为NaN
  • 正确舍入除法和平方根。 确保结果在精确结果的1-3 ulps内比在1/2 ulp内更容易。 一个特别常见的情况是将除法实现为倒数+乘法,这会使您失去一点精度。
  • 更少或没有保护数字。 这是一个不寻常的廉价,但意味着其他操作可以1-2卢比。

BUUUUT ......即使是那些除了blah架构之外的人仍然使用IEEE-754的数字表示。 除了字节排序问题之外,在架构A上描述floatdouble的位基本上保证在架构B上具有相同的含义。

所以只要你关心的只是价值观的代表,你就完全没问题了。 如果您关心跨平台操作的一致性,则可能需要做一些额外的工作。

编辑 :正如Chux在评论中提到的,平台之间常见的额外不一致来源是使用扩展精度,例如x87的80位内部表示。 这与廉价的相反,并且(通过适当的处理)完全符合IEEE-754和C标准,但它同样会导致架构之间的结果不同,甚至在编译器版本之间以及显然是次要的和不相关的代码之间变化。 但是:由于扩展的精度,特定的x86 / x64可执行文件不会在不同的处理器上产生不同的结果。

有一个要检查的宏(自C99起):

C11§6.10.8.3条件特征宏

__STDC_IEC_559__整数常量1,用于表示符合附录F(IEC 60559浮点运算)中的规范。

IEC 60559ISO / IEC / IEEE 60559的缩写)是IEEE-754的另一个名称。

然后,附件F建立C浮动类型和IEEE-754类型之间的映射:

C浮动类型符合IEC 60559格式,如下所示:

  • 浮点类型符合IEC 60559单一格式。
  • 双重类型符合IEC 60559双重格式。
  • long double类型匹配IEC 60559扩展格式,357)否则是非IEC 60559扩展格式,否则是IEC 60559双格式。

我建议您需要仔细查看便携式的定义。

我还建议你对“安全”的定义是不够的。 即使二进制表示(允许字节顺序)没问题,对变量的操作也可能表现不同。 毕竟,浮点数的应用很少,不涉及对变量的操作。

如果您想支持所有已创建的主机架构,那么假设IEEE浮点格式本质上是不安全的。 您将不得不处理支持不同格式的系统,根本不支持浮点的系统,编译器有交换机选择浮点行为的系统(某些行为与非IEEE格式相关联),具有的CPU可选的协处理器(因此浮点支持取决于是否安装了额外的芯片,但CPU的其他变体是相同的),在软件中模拟浮点运算的系统(某些此类软件仿真器可在运行时配置),以及具有错误或不完整浮点实现的系统(可能是也可能不是基于IEEE的)。

如果你愿意将自己限制在2000年后的年份硬件,那么你的风险会降低但不是零。 实际上,该年份的所有CPU都以某种forms支持IEEE。 但是,您仍然(与旧的CPU一样)需要考虑您希望支持的浮点运算,以及您愿意接受的权衡取舍。 不同的CPU(或软件仿真)具有比其他CPU更不完整的浮点实现,并且一些默认配置为不支持某些function – 因此有必要更改设置以启用某些function,这些function可能会影响您的性能或正确性码。

如果您需要在应用程序之间共享浮点值(可能在具有不同function的不同主机上,使用不同的编译器构建等),那么您将需要定义协议。 该协议可能涉及IEEE格式,但您的所有应用程序都需要能够处理协议与其本机表示之间的转换。

几乎所有常见的架构现在都使用IEEE-754,这不是标准所要求的。 曾经有旧的非IEE-754架构,有些可能仍然存在。

如果唯一的要求是交换网络数据,我的建议是:

  • 如果定义了__STDC_IEC_559__ ,则仅对字节使用网络顺序,并假设您对float和double有标准IEE-754。
  • 如果__STDC_IEC_559__ ,请使用特殊的交换格式,可能是IEE-754 – 单个协议 – 或其他任何 – 需要协议指示。

像其他人提到的那样,有__STDC_IEC_559__宏,但它不是很有用,因为它只是由完全实现C标准中相应附件的编译器设置的。 有些编译器只实现了一个子集,但仍然具有(大部分)可用的IEEE浮点支持。

如果您只关心二进制表示,则应编写一个function测试来检查某些浮点数的位模式。 就像是:

 #include  #include  typedef union { double d; uint64_t i; } double_bits; int main() { double_bits b; bd = 2.5; if (bi != UINT64_C(0x4004000000000000)) { fprintf(stderr, "Not an IEEE-754 double\n"); return 1; } return 0; } 

用不同的指数,尾数和符号检查几个数字,你应该是安全的。 由于这些测试并不昂贵,您甚至可以在运行时运行它们一次。

严格地说,假设浮点支持是不安全的; 一般来说,绝大多数平台都会支持它。 值得注意的例外包括(现已弃用)在Alpha芯片上运行的VMS系统

如果你有豪华的运行时检查,请考虑由威廉卡汉编写的paranoia审查工具paranoia

编辑:听起来您的应用程序更关注二进制格式,因为它们与存储和/或序列化有关。 我建议缩小范围,选择支持此function的第三方库。 你可能会比Google Protocol Buffers更糟糕。