【问题标题】:How to portably write double data type to file in C如何可移植地将双数据类型写入 C 中的文件
【发布时间】:2019-06-04 18:16:10
【问题描述】:

我需要以可移植的方式将double 值存储在文件中。我知道我可以将它们写成人类可读的形式,比如1.23456789,但我希望通过将它们写成二进制来节省空间。

我知道如何将二进制文件写入文件,但是有没有一种方法可以使生成的文件与编译和执行代码的机器无关?我希望能够以这种方式跨机器读取/写入此类文件。

【问题讨论】:

  • 简单的常规方法是使用跨平台序列化库,如 msgpack 或 Google 协议缓冲区
  • 有意思,我去看看。
  • 如果您需要序列化的 only 东西是双倍的,那就太矫枉过正了,但这是极不可能的。
  • 如果您可以假设所涉及的系统对double 使用相同的二进制格式(或者至少使用某种二进制格式并且每个系统都能够表示所有必需的值),然后使用%a 格式的输入和输出。这使用十六进制表示法,可以轻松准确地表示值(即,不需要任何舍入)。
  • 如果您需要进一步压缩,并且可以再次假设二进制基数,则在二进制中写入符号位、有效位和指数位。您可以使用frexp 获得有效位和指数位。您需要决定如何编码 NaN 和无穷大。

标签: c file io binary


【解决方案1】:

你总是可以根据 IEEE 754 将数字外化。这也是当前 CPU 中最常用的格式,但是如果你想要便携,你必须在所需的部分中计算相关字段(符号/指数/分数)以编程方式精确,而不是直接使用当前平台的内存表示。

另一种选择是使用定点数。如果您要表示的数字范围和精度允许,这可能是更简单的选择。

【讨论】:

    【解决方案2】:

    如果您用于序列化 double 值的机器对 double 值使用 IEEE 754 双精度,您可以分别存储符号、指数和尾数,以便您可以使用该信息来重建在您要加载的任何其他系统中的双倍值:

    typedef union _DI
    {
        double d;
        uint64_t bits;
    } DI;
    
    
    DI foo;
    uint64_t mask = 0x8000000000000000, sign, exp, mantissa, base;
    int i;
    
    foo.d = 3.141;
    sign = !!(foo.bits & mask);
    
    mask = 0x7FF0000000000000;
    exp = ((foo.bits & mask) >> 52) - 1023;
    
    mask = 0x000FFFFFFFFFFFFF;
    mantissa = (foo.bits & mask);
    

    请注意尾数也必须是normalized

    【讨论】:

    • C 有frexp 提供有效数和指数;不需要联合或采用 IEEE-754 格式。
    【解决方案3】:

    简单的答案是否定的。没有以二进制形式写入浮点数的二进制可移植方式。即使您遵循 IEEE-752 文档,您也会发现您可以以不同的顺序存储符合浮点的字节(例如整数的大/小端形式)

    有几种 IETF 协议(最著名的 IPFIX 协议)定义了一种格式,用于将 IEEE-752 浮点数传输为所谓的(那里)网络格式。这会强制将数字以从大到小的重量写入,但例如这会强制低端机器(如英特尔的)在读取/写入线路时交换字节。

    那么,人们在做什么呢?好吧,如果你想保存你的数据,你最好定义你自己的格式并在你的项目中始终遵循它。以一种独立于架构的方式。如果您有幸成为第一个,当其他人需要访问您的数据时,您可以告诉他们这些数据的存储方式,所有人都可以遵循您的规范,而不是您必须适应他们的规范。

    【讨论】:

      猜你喜欢
      • 2011-05-02
      • 1970-01-01
      • 2014-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-21
      相关资源
      最近更新 更多