Answers:
差异很大。
顾名思义,a double
的精度是[1]的 2倍。通常,a 的精度为15位小数,而a 的精度为7位。float
double
float
计算位数的方法如下:
double
有52个尾数位+ 1个隐藏位:log(2 53)÷log(10)= 15.95位
float
有23个尾数位+ 1个隐藏位:log(2 24)÷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
,因此float
比double
简单的计算(例如计算60的阶乘),使用可以更容易地达到“无穷大”(即特殊的浮点数)。
在测试过程中,可能有几个测试用例包含这些庞大的数字,如果您使用浮点数,则可能导致程序失败。
当然,有时甚至double
不够精确,因此我们有时会得到long double
[1](上面的示例在Mac上为9.000000000000000066),但是所有浮点类型都存在舍入误差,因此精度非常重要(例如,金钱)处理),您应该使用int
或分数类。
此外,+=
由于误差会迅速累积,因此请勿用于对大量浮点数求和。如果您使用的是Python,请使用fsum
。否则,尝试实现Kahan求和算法。
[1]:C和C ++标准没有规定的表示float
,double
和long double
。所有这三个都可能实现为IEEE双精度。但是,对于大多数体系结构(gcc,MSVC,x86,x64,ARM)float
,确实是IEEE单精度浮点数(binary32),并且double
是 IEEE双精度浮点数(binary64)。
标准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之间的浮点数是精度最高的数字。
给定一个二次方程:x 2 − 4.0000000 x + 3.9999999 = 0,精确到10个有效数字的根是r 1 = 2.000316228和r 2 = 1.999683772。
使用float
和double
,我们可以编写一个测试程序:
#include <stdio.h>
#include <math.h>
void dbl_solve(double a, double b, double c)
{
double d = b*b - 4.0*a*c;
double sd = sqrt(d);
double r1 = (-b + sd) / (2.0*a);
double r2 = (-b - sd) / (2.0*a);
printf("%.5f\t%.5f\n", r1, r2);
}
void flt_solve(float a, float b, float c)
{
float d = b*b - 4.0f*a*c;
float sd = sqrtf(d);
float r1 = (-b + sd) / (2.0f*a);
float r2 = (-b - sd) / (2.0f*a);
printf("%.5f\t%.5f\n", r1, r2);
}
int main(void)
{
float fa = 1.0f;
float fb = -4.0000000f;
float fc = 3.9999999f;
double da = 1.0;
double db = -4.0000000;
double dc = 3.9999999;
flt_solve(fa, fb, fc);
dbl_solve(da, db, dc);
return 0;
}
运行程序给我:
2.00000 2.00000
2.00032 1.99968
请注意,数字并不大,但是您仍然可以使用取消效果float
。
(实际上,以上并不是使用单精度或双精度浮点数求解二次方程的最佳方法,但是即使使用更稳定的方法,答案也保持不变。)
类型为float的32位长,精度为7位。虽然它可以存储非常大或非常小的范围(+/- 3.4 * 10 ^ 38或* 10 ^ -38)的值,但它只有7位有效数字。
类型为double的64位长,具有较大的范围(* 10 ^ + /-308)和15位精度。
long double类型的标称值为80位,尽管给定的编译器/ OS配对可以将其存储为12-16字节以用于对齐。长双数的指数非常大,应该具有19位数字的精度。微软以其无限的智慧将长整数限制为8个字节,与普通双倍相同。
一般来说,当您需要浮点值/变量时,只需使用double类型。默认情况下,表达式中使用的文字浮点值将被视为双精度,大多数返回浮点值的数学函数将返回双精度。如果只使用double,则可以避免很多麻烦和类型转换。
我刚遇到一个错误,使我花了很长时间才找出来,并可能为您提供浮点精度的一个很好的例子。
#include <iostream>
#include <iomanip>
int main(){
for(float t=0;t<1;t+=0.01){
std::cout << std::fixed << std::setprecision(6) << t << std::endl;
}
}
输出是
0.000000
0.010000
0.020000
0.030000
0.040000
0.050000
0.060000
0.070000
0.080000
0.090000
0.100000
0.110000
0.120000
0.130000
0.140000
0.150000
0.160000
0.170000
0.180000
0.190000
0.200000
0.210000
0.220000
0.230000
0.240000
0.250000
0.260000
0.270000
0.280000
0.290000
0.300000
0.310000
0.320000
0.330000
0.340000
0.350000
0.360000
0.370000
0.380000
0.390000
0.400000
0.410000
0.420000
0.430000
0.440000
0.450000
0.460000
0.470000
0.480000
0.490000
0.500000
0.510000
0.520000
0.530000
0.540000
0.550000
0.560000
0.570000
0.580000
0.590000
0.600000
0.610000
0.620000
0.630000
0.640000
0.650000
0.660000
0.670000
0.680000
0.690000
0.700000
0.710000
0.720000
0.730000
0.740000
0.750000
0.760000
0.770000
0.780000
0.790000
0.800000
0.810000
0.820000
0.830000
0.839999
0.849999
0.859999
0.869999
0.879999
0.889999
0.899999
0.909999
0.919999
0.929999
0.939999
0.949999
0.959999
0.969999
0.979999
0.989999
0.999999
如您所见,在0.83之后,精度大大降低。
但是,如果我将其设置t
为double,则不会发生此类问题。
我花了五个小时才意识到这个小错误,这毁了我的程序。
double
在这里使用不是一个好的解决方案。您可以int
进行计数并进行内部乘法以获得浮点值。
使用浮点数时,您不能相信本地测试将与在服务器端进行的测试完全相同。您的本地系统以及最终测试的运行环境和编译器可能有所不同。在某些TopCoder竞赛中,我曾多次看到此问题,尤其是当您尝试比较两个浮点数时。