IEEE 754/IEC 559

IEEE 754/iec 559

IEEE 754 浮点格式是否跨平台定义明确?在位格式和字节顺序方面?

我愿意将以下内容添加到我的代码中(对于初始版本):

static_assert(std::numeric_limits<float>::is_iec559, "Only support IEC 559 (IEEE 754) float");
static_assert(sizeof(float) * CHAR_BIT == 32, "Only support float => Single Precision IEC 559 (IEEE 754)");

static_assert(std::numeric_limits<double>::is_iec559, "Only support IEC 559 (IEEE 754) double");
static_assert(sizeof(float) * CHAR_BIT == 64, "Only support double => Double Precision IEC 559 (IEEE 754)");

static_assert(std::numeric_limits<long double>::is_iec559, "Only support IEC 559 (IEEE 754) long double");
static_assert(sizeof(float) * CHAR_BIT == 128, "Only support long double  => Exteneded Precision IEC 559 (IEEE 754)");
//  More asserts if required.
//  I noticed my current system has a sizeof(long double) => 128
//  But numeric_limits<long double>::digits  => 63
//  So we are not storing quad precision floats only extended.

如果我以二进制格式编写我的 float/double/long double,这些可以在系统之间传输而无需进一步解释。即...

void write(std::ostream& stream, double value)
{
     stream.write(reinterpret_cast<char const*>(&value), 8);
}

....

double read(std::istream& stream)
{
     double   value;
     stream.read(reinterpret_cast<char*>(&value), 8);
     return value;
}

或者我是否需要将 double 分解为整数部分以便传输(如 this answer 所建议):

这里的区别是我愿意将我支持的表示形式限制为 IEEE-754 这会基本上解决我的浮点值二进制存储问题还是我需要采取进一步的步骤?

注意:对于不符合标准的平台(当我找到它们时),我愿意对代码进行特殊处理,以便它们 read/write IEEE-754 成为本地表示。但我想知道 bit/endian 是否足够定义跨平台以支持 storage/transport。

首先,您可能想要更改代码,使其正确检查字体大小...

static_assert(std::numeric_limits<float>::is_iec559, "Only support IEC 559 (IEEE 754) float");
static_assert(sizeof(float) * CHAR_BIT == 32, "Only support float => Single Precision IEC 559 (IEEE 754)");

static_assert(std::numeric_limits<double>::is_iec559, "Only support IEC 559 (IEEE 754) double");
static_assert(sizeof(double) * CHAR_BIT == 64, "Only support double => Double Precision IEC 559 (IEEE 754)");

static_assert(std::numeric_limits<long double>::is_iec559, "Only support IEC 559 (IEEE 754) long double");
static_assert(sizeof(long double) * CHAR_BIT == 128, "Only support long double  => Exteneded Precision IEC 559 (IEEE 754)");

事实是,IEEE-754 不要求 long double 为 128 位长。根据编译器和平台的不同,这种类型的长度可能会有所不同。但是它确实指定了 binary128,编译器可能支持也可能不支持,具体取决于平台和实现(gcc 有一个非标准的 __float128 类型)。该标准只要求 long double 至少与 double 一样精确,使其通常为 80 位长 (gcc) 或 64 位 (VS)。

如果您将支持的表示形式限制为 IEEE-754,您应该 运行 不会遇到任何问题。

位格式定义明确,但并非所有机器都是小端格式。 IEEE 标准也不要求浮点数是特定的字节序。你可以运行下面的程序来查看double42.0的字节模式:

#include <stdio.h>
#include <numeric>
#include <limits>
using namespace std;

int main() {
  double d = 42;
  printf("%i\n", std::numeric_limits<double>::is_iec559);
  for (char *c = (char *)&d; c != (char *)(&d+1); c++) {
    printf("%02hhx ", *c);
  }
  printf("\n");
}

在使用 g++ 3.4.5 的旧的、未维护的 Sun 机器上,这会打印

1
40 45 00 00 00 00 00 00

在 x86_64 机器上 运行 使用更新的 g++:

1
00 00 00 00 00 00 45 40

要可移植地读写 IEEE 754,请使用这些例程。 如果平台不是 IEEE 754,您可能会丢失几位,但是 你仍然会得到最接近的代表。

https://github.com/MalcolmMcLean/ieee754