为什么是 100000000000000000!= 10000000000000000000
Why is 10000000000000000 != 10000000000000000?
首先,使用C++在Visual Studio中查看以下代码:
float a = 10000000000000000.0;
float b = a - 10000000000000000.0;
打印出来时,结果是:
a = 10000000272564224.000000
b = 272564224.000000
在"调试"下的"监视"中查看它们时,结果是:
-Name- -Value- -Type-
a 1.0000000e+016 float
b 2.7256422e+008 float
前问题:我确定 100000000000000000.0 在 float
的范围内。为什么我们不能使用 float
获得正确的 a/b?
后续问题:对于预提问,基于所有伟大的以下答案。我知道原因是 32 位浮点数的准确度约为 7 位,因此超过前 6-7 位,所有投注都关闭了。这就是为什么数学不成功,打印这些大数字看起来是错误的。我必须使用双倍才能获得更高的准确性。那么,为什么浮点声称能够处理大量数据,同时我们不能信任它呢?
您使用的巨大数字确实在浮点数的"范围内",但并非所有数字都在浮点数的"精度"范围内。 32 位浮点数的准确度约为 7 位,因此超过前 6-7 位,所有投注都关闭。 这就是为什么数学不成功的原因,当你使用这些大数字时,打印看起来"错误"。 如果您想要更高的准确性,请使用双精度。 有关详细信息,请参阅 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 <stdio.h>
int main()
{
double a = 10000000000000000.0;
double b = a - 10000000000000000.0;
printf("%fn%f", a, b);
}
示例 http://ideone.com/rJN1QI
您的困惑是由隐式转换和float
缺乏准确性引起的。
让我为您填写隐式转换:
float a = (float)10000000000000000.0;
float b = (float)((double)a - 10000000000000000.0);
这会将文字double
转换为float
,它最接近的是10000000272564224。然后减法是用double
而不是float
执行的,所以第二个 100000000000000000.0 不会失去精度。
我们可以使用 nextafter
函数来更好地了解浮点类型的精度。 nextafter
有两个论点;它将相邻的可表示数字返回到其第一个参数,沿其第二个参数的方向。
值10000000000000000.0
(或1.0e16
)完全在类型float
的可表示值范围内,但该值本身不能精确表示。
下面是一个说明该问题的小程序:
#include <math.h>
#include <stdio.h>
int main()
{
float a = 10000000000000000.0;
double d_a = 10000000000000000.0;
printf(" %20.2fn", nextafterf(a, 0.0f));
printf("a = %20.2fn", a);
printf(" %20.2fn", nextafterf(a, 1.0e30f));
putchar('n');
printf(" %20.2fn", nextafter(d_a, 0.0));
printf("d_a = %20.2fn", d_a);
printf(" %20.2fn", nextafter(d_a, 1.0e30));
putchar('n');
}
这是我系统上的输出:
9999999198822400.00
a = 10000000272564224.00
10000001346306048.00
9999999999999998.00
d_a = 10000000000000000.00
10000000000000002.00
如果使用类型 float
,则最接近10000000000000000.00
的是 10000000272564224.00
。
但是在你的第二个声明中:
float b = a - 10000000000000000.0
减法在类型double
中完成;常数10000000000000000.0
已经是双精度类型,并且a
被提升到double
以匹配。因此,这需要存储在a
中的1.0e16
的差近似,并从中减去可以用类型 double
表示的更好的近似(实际上是精确的)。
- 没有找到相关文章