将 float 转换为 double 时会丢失精度,即使对于具有精确二进制表示的值也是如此

问题描述 投票:0回答:1

用于解释浮点的二进制与十进制表示的典型示例是值

0.3
:

float asFloat = 0.3;    // <-- 0.300000012
double asDouble = 0.3;  // <-- 0.29999999999999999
double asCastedDouble = static_cast<double>( asFloat );  // <-- 0.30000001192092896

asFloat
asDouble
是文字
0.3
最接近的二进制表示形式。天真的目光可能会对
asCastedDouble
的值感到惊讶,但随后我们会记得它是浮点值的最接近表示,而不是文字,所以这是有道理的。然而,我确实想知道为什么强制转换的双精度表示形式与尾数中添加零位的浮点表示形式(已经是二进制的)不同,十进制表示形式会转换为
0.300000011200000000
,但这是一个单独的问题。

现在考虑不同文字的第二个示例:

float asFloat2 = -0.488730401;    // <-- -0.488730401 
double asDouble2 = -0.488730401;  // <-- -0.48873040099999998
double asCastedDouble2 = static_cast<double>( asFloat2 );   // <-- -0.48873040080070496

这个文字恰好可以用二进制精确表示,因此

asFloat2
与我们的文字值相同。就像在最后一个例子中一样,我想知道为什么
asDouble2
asFloat2
“不太”准确,而不是与尾数中额外的零位相同,但我会让它滑动。 现在的问题是:为什么
asCastedDouble2
是这个值?它与前面的示例不同,因为我们在浮点型中引入了精度误差,然后将其带入双精度型中。然而,在这种情况下,浮点值与文字相同,那么 as
asCastedDouble2
的值从何而来?这显然不是最接近的二进制表示,因为
asDouble2
向我们展示了更接近的表示?

所以我想我的问题是双重的:

  1. 为什么某些可以表示为浮点数的数字不能表示为双精度数?
  2. 可能相关,为什么从 float 转换为 double 时我们会丢失精度?
c++ ieee-754
1个回答
0
投票

没有可表示为浮点数的数字不能表示为双精度数。

您混淆了通常的四舍五入的十进制打印输出和机器内部表示的实际数字。要以十进制形式准确显示 32 位浮点数“0.3”,需要大量的十进制位数。足够的小数位可以准确显示 1/2^24。

参见示例 IEEE 754 Base 转换器,您可以在其中输入您选择的数字并查看 32 位浮点型和 64 位双精度型(精确的十进制、十六进制和二进制)的表示形式。

浮点提升将尾数加倍忠实地补零至 53 位,并将指数范围从 +/-127 扩展至 +/-1023。

© www.soinside.com 2019 - 2024. All rights reserved.