double和long double精度差异的原因是什么?

58 浏览
0 Comments

double和long double精度差异的原因是什么?

我读过双精度和单精度之间的差异。然而,在大多数情况下,floatdouble 看起来是可以互换的,也就是使用其中一个并不会影响结果。这是真的吗?何时可以互换 float 和 double?它们之间有什么区别?

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

C99标准(ISO-IEC 9899 6.2.5 §10)或C++2003标准(ISO-IEC 14882-2003 3.1.9 §8)中有如下规定:

有三种浮点类型:floatdoublelong double。类型double提供的精度至少与float相同,类型long double提供的精度至少与double相同。类型float的值集是类型double值集的子集;类型double的值集是类型long double值集的子集。

C++标准补充道:

浮点型的值表达式是实现定义的。

我建议您查看博学的计算机科学家应该知道的浮点算术,它深入讲解了IEEE浮点标准。您将了解表示细节,并意识到精度与数量之间存在权衡。浮点表示的精度随数量减少而增加,因此,-1到1之间的浮点数具有最高的精度。

0
0 Comments

巨大的差异。

顾名思义,doublefloat的精度高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更容易“溢出”(即成为一个特殊的浮点数)。

在测试过程中,可能会有一些测试用例包含这些巨大的数字,如果使用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