float 和 double 有什么区别?
float 和 double 有什么区别?
我已经读到过双精度和单精度之间的差异。但在大多数情况下,float
和double
似乎可以互换使用,即使用其中之一似乎不会影响结果。这真的是这样吗?什么情况下可以互换使用float和double?它们之间有什么区别?
以下是标准 C99 (ISO-IEC 9899 6.2.5 §10) 或 C++2003 (ISO-IEC 14882-2003 3.1.9 §8) 所述:
有三种浮点类型:
float
,double
和long double
。类型double
提供了至少与float
一样多的精度,而类型long double
提供了至少与double
一样多的精度。类型float
的值集是类型double
的值集的一个子集;类型double
的值集是类型long double
的值集的一个子集。
C++标准补充说:
浮点类型的值表示是由实现定义的。
我建议看看优秀的计算机科学家应该了解的浮点算术知识,深入探讨IEEE浮点标准。你会了解到表示细节,并意识到精度和数量之间存在权衡。浮点表示的精度随数量的减少而增加,因此-1到1之间的浮点数具有最高的精度。
巨大的差异。
正如其名称所示,double
比float
精度高2倍[1]。通常,double
的精度为15个小数位,而float
的精度为7个。
以下是数字位数的计算方法:
double
有52位隐含位数+1位隐藏位数:log(253)÷log(10) = 15.95位小数
float
有23位隐含位数+1位隐藏位数:log(224)÷log(10) = 7.22位小数
这种精度损失可能导致在进行重复计算时积累更大的截断误差,例如:
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,因此在计算简单的事情(例如计算60的阶乘)时,使用float
可以更容易地达到"无穷大"(即一种特殊的浮点数)。
在测试中,可能会有一些测试用例包含这些巨大的数字,如果使用浮点数,则可能会导致程序失败。
当然,有时候,即使是double
也不够准确,因此我们有时会使用long double
[1](例如上面的例子在Mac上给出的结果是9.000000000000000066),但所有浮点数类型都会受到舍入误差的影响,因此如果精度非常重要(例如处理货币),应该使用int
或分数类。
此外,不要使用+=
来求和大量浮点数,因为误差会快速累积。如果你在使用Python,可以使用fsum
。否则,尝试实现Kahan求和算法。
[1]:C和C++标准没有规定float
,double
和long double
的表示方式。三者都可能被实现为IEEE double-precision。然而,对于大多数体系结构(如gcc,MSVC;x86,x64,ARM),float
确实是IEEE single-precision浮点数(binary32),而double
是IEEE double-precision浮点数(binary64)。