为什么是10000000000000000!= 10000000000000000?

首先,使用C ++查看Visual Studio中的以下代码:

float a = 10000000000000000.0; float b = a - 10000000000000000.0; 

打印出来时,结果是:

 a = 10000000272564224.000000 b = 272564224.000000 

在Debug下的Watch中查看它们时,结果是:

 -Name- -Value- -Type- a 1.0000000e+016 float b 2.7256422e+008 float 

提问 :我确信10000000000000000.0float范围内。 为什么我们无法使用float获得正确的a / b


后续问题 :对于前置问题,基于所有伟大的以下答案。 我知道原因是32位浮点数的精度大约为7位数,因此超出前6-7位数,所有投注均已关闭。 这就是为什么数学不能解决问题,并且这些大数字的打印看起来不对。 我必须使用double来获得更高的准确性。 那么为什么浮动声称能够处理大量数据并且同时我们不能相信它?

您使用的数字确实在float的“范围”内,但并非所有数字都在float的“精度”范围内。 32位浮点数的精度约为7位数,因此超出前6-7位数,所有投注均已关闭。 这就是数学无法解决的原因,当你使用这些大数字时打印看起来“错误”。 如果您想要更高的准确度,请使用double。 有关更多信息,请参阅http://en.wikipedia.org/wiki/Floating_point#IEEE_754:_floating_point_in_modern_computers

浮点数大约需要6-7个小数位(分数为23位),因此任何带小数位数的数字只是一个近似值。 这导致了rondom数字。

有关浮点格式精度的更多信息,请访问: http : //en.wikipedia.org/wiki/Single-precision_floating-point_format

对于更新的问题:当需要精度时,不应使用浮点格式。 我们不能只指定更大的内存空间。 处理具有非常大量小数的数字需要非常大量的内存。因此使用更复杂的方法(例如,使用字符串格式然后连续处理字符)。

为了避免这个问题,请使用double ,它给出大约16-17个小数位(对于分数为52位)或long double以获得更高的精度。

 #include  int main() { double a = 10000000000000000.0; double b = a - 10000000000000000.0; printf("%f\n%f", a, b); } 

例如http://ideone.com/rJN1QI

您的混淆是由隐式转换和float的准确性不足引起的。

让我为您填写隐含的转换:

 float a = (float)10000000000000000.0; float b = (float)((double)a - 10000000000000000.0); 

这会将文字double float转换为float ,并且它最接近的是10000000272564224.然后使用double ,而不是float来执行减法,因此第二个10000000000000000.0不会丢失精度。

我们可以使用nextafter函数来更好地了解浮点类型的精度。 nextafter有两个论点; 它将相邻的可表示数字返回到第一个参数,在第二个参数的方向上。

10000000000000000.0 (或1.0e16 )完全在float类型的可表示值范围内 ,但该值本身无法准确表示。

这是一个说明问题的小程序:

 #include  #include  int main() { float a = 10000000000000000.0; double d_a = 10000000000000000.0; printf(" %20.2f\n", nextafterf(a, 0.0f)); printf("a = %20.2f\n", a); printf(" %20.2f\n", nextafterf(a, 1.0e30f)); putchar('\n'); printf(" %20.2f\n", nextafter(d_a, 0.0)); printf("d_a = %20.2f\n", d_a); printf(" %20.2f\n", nextafter(d_a, 1.0e30)); putchar('\n'); } 

这是我的系统输出:

  9999999198822400.00 a = 10000000272564224.00 10000001346306048.00 9999999999999998.00 d_a = 10000000000000000.00 10000000000000002.00 

如果使用float类型,则最接近10000000000000000.0010000000272564224.00

但在你的第二个宣言中:

 float b = a - 10000000000000000.0 

减法是在double类型中完成的; 常量10000000000000000.0已经是double类型,而a被提升为double以匹配。 因此,这需要存储在a1.0e16的差近似值,并从中减去更好的近似值(实际上它是精确的),可以用double类型表示。