7

我的意思是,例如,我有以下以 IEEE-754 单精度编码的数字:

"0100 0001 1011 1110 1100 1100 1100 1100"  (approximately 23.85 in decimal)

上面的二进制数存储在文字字符串中。

问题是,如何将这个字符串转换为 IEEE-754 双精度表示(有点像下面的,但值不一样),而不会丢失精度?

"0100 0000 0011 0111 1101 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010"

这是同一个号码以 IEEE-754 双精度编码。

我尝试使用以下算法首先将第一个字符串转换回十进制数,但它会丢失精度。

num in decimal = (sign) * (1 + frac * 2^(-23)) * 2^(exp - 127)

我在 Windows 平台上使用 Qt C++ 框架。

编辑:我必须道歉,也许我没有清楚地表达这个问题。我的意思是我不知道真正的值 23.85,我只得到了第一个字符串,我想将它转换为双精度表示而不损失精度。

4

5 回答 5

3

好吧:保留符号位,重写指数(减去旧偏差,加上新偏差),并在右边用零填充尾数......

(正如@Mark 所说,您必须单独处理一些特殊情况,即当有偏指数为零或最大值时。)

于 2012-09-17T20:44:33.427 回答
2

首先,+1 用于识别二进制输入。

其次,这个数字并不代表 23.85,而是略少。如果将它的最后一个二进制数字从 翻转01,这个数字仍然不能准确地表示 23.85,但会稍微多一些。这些差异不能在浮点数中充分捕捉,但可以在双精度中近似捕捉。

第三,你认为你失去的东西叫做准确性,而不是精确度。数字的精度总是通过从单精度到双精度的转换而增长,而精度永远不会通过转换来提高(你的不准确的数字仍然不准确,但是额外的精度使它更加明显)。

我建议在显示(或记录)数字之前转换为浮点数或舍入或添加一个非常小的值,因为视觉外观是您通过提高精度真正失去的东西。

抵制在强制转换后立即舍入并在后续计算中使用舍入值的诱惑——这在循环中尤其危险。虽然这似乎可以纠正调试器中的问题,但累积的额外不准确性可能会进一步扭曲最终结果。

于 2012-09-17T20:49:29.537 回答
2

IEEE-754(和一般的浮点数)不能以全精度表示周期性二进制十进制数。即使它们实际上是整数分子和分母相对较小的有理数,也不是。一些语言提供了一种可以做到的有理类型(它们也是支持无界精度整数的语言)。

因此,您发布的这两个数字不是同一个数字。

它们实际上是:

10111.11011001100110011000000000000000000000000000000000000000 ... 10111.110110011001100110011001100110011001100110011010000000 ...

其中...表示 s 的无限序列0

Stephen Canon 在上面的评论中为您提供了相应的十进制值(没有检查它们,但我没有理由怀疑他是否正确)。

因此,您想要进行的转换无法完成,因为单精度数字没有您需要的信息(您无法知道该数字是否实际上是周期性的,或者只是看起来像是因为恰好有重复) .

于 2012-09-17T21:09:23.060 回答
1

将字符串转换为实际的浮点数可能是最简单的,将其转换为双精度数,然后再将其转换回字符串。

于 2012-09-17T20:46:48.637 回答
-1

二进制浮点通常不能准确地表示十进制小数值。从十进制小数值到二进制浮点的转换(参见 William D.Clinger 的“如何准确读取浮点数”中的“Bellerophon”)以及从二进制浮点转换回十进制值(参见“Dragon4”在 Guy L.Steele Jr. 和 Jon L.White 的“如何准确地打印浮点数”中)产生了预期的结果,因为一个将十进制数转换为最接近的可表示二进制浮点数,另一个控制错误以知道哪个它来自的十进制值(在 David Gay 的dtoa.c中,两种算法都得到了改进并变得更加实用。算法是恢复的基础std::numeric_limits<T>::digits10存储在类型中的浮点值的十进制数字(可能除了尾随零)T

不幸的是,将 a 扩展为floatdouble值造成严重破坏:尝试格式化新数字在许多情况下不会产生十进制原始数字,因为float用零填充的值与最接近的doubleBellerophon 不同,因此 Dragon4 期望。但是,基本上有两种方法可以很好地工作:

  1. 正如有人建议将 转换float为字符串并将此字符串转换为double. 这不是特别有效,但可以证明可以产生正确的结果(当然,假设正确实现了并非完全微不足道的算法)。
  2. 假设您的值在一个合理的范围内,您可以将它乘以 10 的幂,使得最低有效十进制数字不为零,将此数字转换为整数,将此整数转换为 a double,最后将得到的 double 除以10 的原始幂。我没有证据证明这会产生正确的数字,但是对于我感兴趣并且我想准确存储在 a 中的值范围float,这是可行的。

避免这个问题的一种合理方法是首先使用Decimal TR中为 C++ 描述的十进制浮点值。不幸的是,这些还不是标准的一部分,但我已经向 C++ 标准化委员会提交了一份提案以改变它。

于 2012-09-17T22:58:45.220 回答