Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何将float转换为double(都存储在IEEE-754表示中),而不丢失精度?_C++_Qt_Floating Point_Double_Ieee 754 - Fatal编程技术网

C++ 如何将float转换为double(都存储在IEEE-754表示中),而不丢失精度?

C++ 如何将float转换为double(都存储在IEEE-754表示中),而不丢失精度?,c++,qt,floating-point,double,ieee-754,C++,Qt,Floating Point,Double,Ieee 754,我的意思是,例如,我用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

我的意思是,例如,我用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)
我曾尝试使用以下算法首先将第一个字符串转换回十进制数,但它失去了精度

num in decimal = (sign) * (1 + frac * 2^(-23)) * 2^(exp - 127)
<>我在Windows平台上使用Qt+C++框架。 编辑:我必须道歉,也许我没有把问题表达清楚。
我的意思是,我不知道真实值23.85,我只得到了第一个字符串,我想将其转换为双精度表示,而不损失精度。

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


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

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

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

第二,这个数字并不代表23.85,但略低。如果将其最后一个二进制数字从
0
翻转到
1
,则该数字仍不能准确表示23.85,但略高一些。这些差异无法在浮点中充分捕获,但可以在双精度浮点中大致捕获

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

我建议在显示(或记录)数字之前转换为浮点或四舍五入或添加一个非常小的值,因为增加精度确实会损失视觉外观

num in decimal = (sign) * (1 + frac * 2^(-23)) * 2^(exp - 127)
请抵制在强制转换后立即取整的诱惑,并在后续计算中使用取整的值-这在循环中尤其危险。虽然这似乎可以纠正调试器中的问题,但累积的额外误差可能会进一步扭曲最终结果。

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

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

事实上,它们是:

10111.110110011000000000000000000000000000000000。。。 10111.11011001100110000000000

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

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


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

一般来说,二进制浮点数不能,精确表示小数点的值。从小数到二进制浮点数的转换(参见William D.Clinger的“如何准确读取浮点数”中的“Bellerophon”)以及从二进制浮点数到小数的转换(参见Guy L.Steele Jr.和Jon L.White的“如何准确打印浮点数”中的“Dragon4”)产生预期的结果,因为一个将十进制数转换为最接近的可表示二进制浮点,另一个控制错误以知道它来自哪个十进制值(David Gay对这两种算法进行了改进,使其更加实用。这些算法是从存储在类型
T
中的浮点值恢复
std::numeric\u limits::digits10
十进制数字(可能的尾随零除外)的基础

不幸的是,将
float
扩展为
double
会破坏该值:尝试格式化新数字在许多情况下不会产生十进制原始值,因为用零填充的
float
与最近的
double
Bellerophon将创建不同,因此,Dragon4期望然而,有两种方法相当有效:

  • 正如有人建议的那样,将
    float
    转换为字符串,并将该字符串转换为
    double
    。这不是特别有效,但可以证明能够产生正确的结果(当然,假设正确实现了不完全是琐碎的算法)
  • 假设你的值在一个合理的范围内,你可以将它乘以10的幂,使最低有效的十进制数字不为零,将这个数字转换成整数,将这个整数转换成一个
    双精度
    ,最后将得到的双精度除以原来的幂10。我没有证据证明这会产生正确的数字,但是对于我感兴趣并希望准确存储在
    float
    中的值范围,这是可行的
  • <> P>一个避免这种完全问题的合理方法是首先使用如C++所描述的十进制浮点值。不幸的是,这些不是标准的一部分,但我已经向C++标准化委员会提交了一个建议,使其发生变化。