C++ - float 和 double 的区别?

27 浏览
0 Comments

C++ - float 和 double 的区别?

我已经读到了双精度和单精度之间的区别。但是,在大多数情况下,float和double似乎是可以互换的,即使用其中之一不会影响结果。这是真的吗?什么时候float和double可以互换?它们之间有什么区别?

admin 更改状态以发布 2023年5月22日
0
0 Comments

这里是标准的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++标准补充说:

浮点类型的值表示是实现定义的。

我建议您仔细阅读What Every Computer Scientist Should Know About Floating-Point Arithmetic,它深入介绍了IEEE浮点数标准。您将了解表示细节,并意识到有一个在数量级和精度之间取得的权衡。浮点表示的精度随数量级的降低而增加,因此-1和1之间的浮点数具有最高的精度。

0
0 Comments

巨大的差异。

正如其名称所示,double的精度是float的两倍[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++标准没有指定floatdoublelong double的表示方式。有可能三者都实现为IEEE双精度。然而,对于大多数体系结构(gcc、MSVC;x86、x64、ARM),float的确是IEEE单精度浮点数(binary32),而double是IEEE双精度浮点数(binary64)。

0