C++ IEEE 754/iec 559

C++ IEEE 754/iec 559,c++,floating-point,double,ieee-754,C++,Floating Point,Double,Ieee 754,IEEE 754浮点格式是否跨平台定义良好?在位格式和尾数方面 我愿意在我的代码中添加以下内容(对于初始版本): static_assert(std::numeric_limits::is_iec559,“仅支持IEC 559(IEEE 754)浮点”); 静态断言(sizeof(float)*字符位==32,“仅支持float=>单精度IEC 559(IEEE 754)”; 静态断言(标准::数字限制::is_iec559,“仅支持IEC 559(IEEE 754)double”); 静态断言

IEEE 754浮点格式是否跨平台定义良好?在位格式和尾数方面

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

static_assert(std::numeric_limits::is_iec559,“仅支持IEC 559(IEEE 754)浮点”);
静态断言(sizeof(float)*字符位==32,“仅支持float=>单精度IEC 559(IEEE 754)”;
静态断言(标准::数字限制::is_iec559,“仅支持IEC 559(IEEE 754)double”);
静态断言(sizeof(float)*字符位==64,“仅支持双精度=>双精度IEC 559(IEEE 754)”;
静态断言(标准::数字限制::is_iec559,“仅支持IEC 559(IEEE 754)长双精度”);
静态断言(sizeof(float)*字符位==128,“仅支持长双精度=>扩展精度IEC 559(IEEE 754)”;
//如有需要,可提供更多的资产。
//我注意到我当前的系统有一个sizeof(longdouble)=>128
//但是数字限制::数字=>63
//因此,我们不是只存储扩展的四精度浮点。
如果我以二进制格式编写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;
}
void写入(std::ostream&stream,双值)
{
stream.write(重新解释类型和值),8);
}
....
双读(标准::istream&stream)
{
双重价值;
stream.read(重新解释类型和值),8);
返回值;
}
或者我是否需要将双精度分解为整数组件进行传输(如建议的那样):

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


注:对于不符合要求的平台(当我发现它们时),我愿意对代码进行特殊处理,以便它们将IEEE-754读/写到本地表示中。但是我想知道bit/endian是否足够好地跨平台定义,以支持存储/传输。

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

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)");
static_assert(std::numeric_limits::is_iec559,“仅支持IEC 559(IEEE 754)浮点”);
静态断言(sizeof(float)*字符位==32,“仅支持float=>单精度IEC 559(IEEE 754)”;
静态断言(标准::数字限制::is_iec559,“仅支持IEC 559(IEEE 754)double”);
静态断言(sizeof(double)*字符位==64,“仅支持double=>双精度IEC 559(IEEE 754)”;
静态断言(标准::数字限制::is_iec559,“仅支持IEC 559(IEEE 754)长双精度”);
静态断言(sizeof(长双精度)*字符位==128,“仅支持长双精度=>扩展精度IEC 559(IEEE 754)”;
问题是,IEEE-754不要求long double的长度为128位。根据编译器和平台的不同,此类类型的长度可能会有所不同。但是,它确实指定了binary128,编译器可能支持也可能不支持binary128,这取决于平台和实现(gcc有一个非标准的_float128类型)。该标准只要求longdouble至少与double一样精确,使其通常为80位长(gcc)或64位长(VS)


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

位格式定义良好,但并非所有计算机都是little-endian。IEEE标准也不要求浮点数为某个端点。您可以运行以下程序来查看
double
42.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++的x86_64计算机上:

1
00 00 00 00 00 00 45 40

要可移植地读写IEEE 754,请使用以下例程。 如果平台不是IEEE 754,可能会丢失一些位,但是 您仍将获得最接近的可能表示形式


未指定端部。所以你想把所有的东西都转换成大端或小端。@tmyklebu:你有我能读到的说明吗?与我交谈的其他人都说是这样(尽管他们也没有向我展示标准)。我感到困惑。你想要一个引用说另一个引用没有说什么?@tmyklebu:很抱歉,这是错的(我也会犯“除非明确指定,否则我们不能假设”的错误,所以目前我认为我必须考虑到这一点)。但我想理解你为什么这么说(因为我一直听说endianness不是一个因素),这就是为什么我要问这个问题。我想得到一些明确的参考资料,说明如何在内存中看到这一点。正如你所看到的,目前唯一的答案是暗示这不是一个问题(并且没有反对票,尽管1张赞成票也不是响亮的赞成票),我这么说是因为在SPARC上打印出
double
42.0
的字节会给您带来
40 45 00 00
,而在x86_64机器上打印会给您带来
00 00 45 40
。这些是不同的,因为SPARC是big-endian,x86_64是little-endian。std::numeric_limits::digits的值是多少?,但我非常确定这是决定性的证据,证明endianess不是标准的一部分,因此我不能在这个问题中使用简单的技术,必须做一些工作来补偿不同的限制体系结构。@LokiAstari:
数字在两种平台上都是53。除了它不在标准中之外,为什么endianness不是标准的另一个论点是,如果它是标准的一部分,小endian平台就是那些会被拧紧的平台。此外,在任何平台上,用错误的endian表示数字的有效位都不方便。使用小endian的原因与整数加法时的进位有关。换一种方式布置晶体管更有效(这种方式长期以来一直是多余的)。我不确定这会如何影响FP编号的布局,因为大多数系统都会将此功能传递给专门的用户
1
40 45 00 00 00 00 00 00
1
00 00 00 00 00 00 45 40