将浮点值序列化为字符串时是否存在错误传播?

时间:2014-07-03 13:35:59

标签: language-agnostic floating-point

说我用我最喜欢的语言有浮动(或双重)。假设在内存中这个值是根据IEEE 754存储的,比如我用XML或JSON或使用基数10的纯文本序列化这个值。当序列化和反序列化这个值时,我会丢失我的数字的精度吗?我什么时候应该关心这种精确损失?

将数字转换为base64可以防止精度损失吗?

2 个答案:

答案 0 :(得分:6)

这取决于您使用的二进制到十进制转换函数。假设这个函数没有被破坏(它没有理由):

  1. 要么转换为固定精度。像C这样的老式语言提供了这种到十进制的转换。在这种情况下,您应该使用17 significant decimal digits格式。常见的格式是D.DDDDDDDDDDDDDDDDEXXX,其中D和X是十进制数字,点后面有16位数字。这将在类C语言中指定为%.16e。将这样的十进制值转换回最接近的double会产生与最初打印的相同的双倍。
  2. 或者将其转换为最短的十进制表示形式,转换回相同的double。这是一些现代编程语言(例如Java)默认提供的打印功能。在这种情况下,解析十进制表示的属性将返回原始double是自动的。
  3. 在任何一种情况下都不应该失去准确性。这不是因为您使用方法1或2.上面的方法得到原始binary64数字的精确十进制表示:在一般情况下,您没有。这样的精确表示始终存在(因为10是2的倍数),但对于binary64数字,最长可达750位数。

    方法1或2.上面的内容是一个十进制数,更接近原始二进制64号,而不是任何其他二进制64号。这意味着从十进制到二进制64的相反转换将“回滚”到原始

    这是必要的“非拙劣”假设:为了使连续转换返回到原始数字,它们必须分别产生与传递的binary64数字最接近的十进制数,并且最接近的二进制64与传递的十进制数字相对应。在这些条件下,并且在第一次转换时使用适当的小数位数,往返是无损的。


    我应该指出(往返十进制)的转换是非常昂贵的操作。除非结果的人类可读性对您很重要,否则您应该考虑转换为更简单的格式。 C99-style hexadecimal representation for floating-point numbers是转换成本和可读性之间的良好折衷。它不是最紧凑的,但只包含可打印的字符。

答案 1 :(得分:1)

转换为转换回最短形式的最短形式的方法是危险的("往返" .NET中的字符串格式化模式使用这种方法,结果有错误)。可能没有理由不使用十进制到二进制转换方法从精确指定的数值产生大于0.75lsb的结果,从而保证转换将总是产生完美舍入的数值是昂贵的并且在大多数情况下案件不是特别有帮助。最好确保十进制表达式的精确算术值小于要表示的double值的0.25lsb。如果距离double小于0.25lsb的那个被送到一个在0.75lsb范围内返回double的例程,那么后一个例程可以保证产生相同的double doubledouble 1}}给予前者。

简单地找到产生相同{{1}}的最短形式的方法假定任何字符串表示将始终以相同的方式解析,即使所表示的值几乎恰好位于两个相邻{{1}}之间的中间位置值。由于获得完美的舍入结果可能需要读取任意数量的数字(例如1125899906842624.125000 ... 1应该向上舍入到1125899906842624.25),很少有实现容易打扰;如果一个实现将忽略超过某个点的数字,即使这可能产生例如超过.056lsb的方式,在任何情况下都不应该被信任准确到0.50000lsb。