为什么是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.0在float
范围内。 为什么我们无法使用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.00
是10000000272564224.00
。
但在你的第二个宣言中:
float b = a - 10000000000000000.0
减法是在double
类型中完成的; 常量10000000000000000.0
已经是double类型,而a
被提升为double
以匹配。 因此,这需要存储在a
的1.0e16
的差近似值,并从中减去更好的近似值(实际上它是精确的),可以用double
类型表示。