【问题标题】:IEEE 754/iec 559IEEE 754/iec 559
【发布时间】:2015-04-21 22:00:42
【问题描述】:

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;
}

或者我是否需要将双精度数分解为整数分量以进行传输(如this answer 所建议的那样):

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

注意:对于不符合标准的平台(当我找到它们时),我愿意对代码进行特殊处理,以便它们将 IEEE-754 读/写为本地表示。但我想知道位/字节序是否定义得足够好,可以跨平台支持存储/传输。

【问题讨论】:

  • 未指定字节顺序。因此,您需要将所有内容都转换为大端或小端。
  • @tmyklebu:你有我能读到的参考资料吗?我与之交谈的其他人都说是(尽管他们也没有向我展示标准)。
  • 我很困惑。您想要一个说明另一个参考没有说明什么的参考?
  • @tmyklebu:很抱歉出现了错误(我也会犯“除非明确指定我们不能假设”的错误,所以目前我认为我必须考虑到这一点)。但是我想了解您为什么这么说(因为我一直听说字节序不是一个因素),这就是我问这个问题的原因。我想获得一些明确的参考,说明我如何期望在内存中看到这一点。如您所见,目前唯一的答案是暗示这不是问题(并且没有反对票,尽管 1 票赞成也不是响亮的支持)。
  • 好吧,我这么说是因为在 SPARC 上打印出 double 42.0 的字节会得到 40 45 00 00 00 00 00 00,而在 x86_64 机器上打印会得到 00 00 00 00 00 00 45 40。这些是不同的,因为 SPARC 是 big-endian 而 x86_64 是 little-endian。

标签: c++ floating-point double ieee-754


【解决方案1】:

首先,您可能想要更改代码,以便正确检查类型大小...

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,您应该不会遇到任何问题。

【讨论】:

    【解决方案2】:

    位格式定义明确,但并非所有机器都是小端的。 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
    

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

    1
    00 00 00 00 00 00 45 40
    

    【讨论】:

    • std::numeric_limits&lt;double&gt;::digits的值是多少
    • 但我很确定这是字节序不是标准的一部分的确凿证据,因此我不能在问题中使用简单的技术,必须做一些工作来补偿不同的架构。
    • @LokiAstari:digits 在两个平台上都是 53。除了它不在标准中之外,为什么字节序不是标准的另一个论点是,如果它是标准的一部分,little-endian 平台会被搞砸。此外,在任何平台上以错误的字节序表示数字的有效位也是很不方便的。
    • 小端的原因与整数加法时的进位有关。以相反的方式布置晶体管更有效(这早已成为多余的东西)。这如何影响 FP 编号的布局我不确定,因为大多数系统将此功能传递给独立于主 CPU 的专用单元。所以我不确定为什么内存中 FP 数字的布局无论如何都会影响系统(但我不是硬件工程师)。据我所知,它只是与整数一致(我想这有其优点)。
    【解决方案3】:

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

    https://github.com/MalcolmMcLean/ieee754

    【讨论】:

      猜你喜欢
      • 2019-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-06
      • 2012-03-14
      • 2014-10-18
      • 1970-01-01
      相关资源
      最近更新 更多