我已经了解了 double 和单精度之间的区别。然而,在大多数情况下,float
和 double
似乎可以互换,即使用其中一个似乎不会影响结果。真的是这样吗? float 和 double 何时可以互换?它们之间有什么区别?
巨大的差异。
顾名思义,double
精度是 float
的 2 倍[1]。一般来说,double
有 15 位精度,而 float
有 7。
位数的计算方法如下:
double
has 52 mantissa bits + 1 hidden bit: log(253)÷log(10) = 15.95 digits
float
has 23 mantissa bits + 1 hidden bit: log(224)÷log(10) = 7.22 digits
这种精度损失可能会导致在重复计算时累积更大的截断误差,例如
float a = 1.f / 81;
float b = 0;
for (int i = 0; i < 729; ++ i)
b += a;
printf("%.7g\n", b); // prints 9.000023
同时
double a = 1.0 / 81;
double b = 0;
for (int i = 0; i < 729; ++ i)
b += a;
printf("%.15g\n", b); // prints 8.99999999999996
另外,float的最大值约为3e38
,而double约为1.7e308
,所以使用float
可以达到“无穷大” (即一个特殊的 float )比 double
更容易做一些简单的事情,例如计算 60 的阶乘。
在测试过程中,可能有几个测试用例包含这些巨大的数字,如果使用 float ,可能会导致程序失败。
当然,有时候,即使 double
也不够准确,因此我们有时会有 long double
[1] (上面的例子在 Mac 上给出 9.000000000000000066),但所有浮点类型都存在 舍入误差,因此如果精度非常重要(例如货币处理),您应该使用 int
或分数类。
此外,不要使用 +=
对大量 float 求和,因为错误会迅速累积。如果您使用的是 Python,请使用 fsum
。否则,尝试执行 Kahan summation algorithm .
[1]:C 和 C++ 标准没有指定 float
、double
和 long double
的表示。有可能所有三个都实现为 IEEE double 。尽管如此,对于大多数架构(gcc、MSVC;x86、x64、ARM)float
is 确实是 IEEE 单精度 float (binary32),而 double
是一个IEEE double float (binary64)。
我是一名优秀的程序员,十分优秀!