我读过关于双精度和单精度之间的区别。然而,在大多数情况下,float和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设为双倍,这样的问题就不会发生。

我花了五个小时才意识到这个小错误,它毁了我的程序。

其他回答

给定二次方程:x2−4.0000000 x + 3.9999999 = 0, 10位有效数字的精确根为:r1 = 2.000316228, r2 = 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仍然可以得到抵消效果。

(事实上,上面的方法并不是用单精度浮点数或双精度浮点数求解二次方程的最佳方法,但即使使用更稳定的方法,答案也不会改变。)

我刚刚遇到了一个错误,我花了很长时间才弄清楚,这可能会给你一个浮点精度的好例子。

#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类型的精度是float类型的两倍,范围是float类型的三倍(取决于你如何计算)。

但也许更重要的是质的差异。float类型具有良好的精度,无论您正在做什么,这通常都足够好。另一方面,Type double具有出色的精度,无论你在做什么,它几乎总是足够好。

结果是,几乎总是应该使用类型double,这一点并不广为人知。除非你有一些特别的需要,否则你几乎不应该使用float类型。

As everyone knows, "roundoff error" is often a problem when you're doing floating-point work. Roundoff error can be subtle, and difficult to track down, and difficult to fix. Most programmers don't have the time or expertise to track down and fix numerical errors in floating-point algorithms — because unfortunately, the details end up being different for every different algorithm. But type double has enough precision such that, much of the time, you don't have to worry. You'll get good results anyway. With type float, on the other hand, alarming-looking issues with roundoff crop up all the time.

And the thing that's not necessarily different between type float and double is execution speed. On most of today's general-purpose processors, arithmetic operations on type float and double take more or less exactly the same amount of time. Everything's done in parallel, so you don't pay a speed penalty for the greater range and precision of type double. That's why it's safe to make the recommendation that you should almost never use type float: Using double shouldn't cost you anything in speed, and it shouldn't cost you much in space, and it will almost definitely pay off handsomely in freedom from precision and roundoff error woes.

(尽管如此,当你在微控制器上进行嵌入式工作或编写针对GPU优化的代码时,你可能需要float类型的“特殊需求”之一。在这些处理器上,double类型可能会非常慢,或者几乎不存在,所以在这种情况下,程序员通常会选择float类型来提高速度,并可能为精度付出代价。)

float类型,长度为32位,精度为7位。虽然它可以存储非常大或非常小的范围(+/- 3.4 * 10^38或* 10^-38)的值,但它只有7位有效数字。

类型double, 64位长,具有更大的范围(*10^+/-308)和15位精度。

类型long double名义上是80位,尽管给定的编译器/操作系统配对可能会将其存储为12-16字节以进行对齐。长双精度数的指数大得离谱,应该有19位精度。微软以其无限的智慧,将long double限制为8字节,与普通double相同。

一般来说,当需要浮点值/变量时,只需使用double类型。默认情况下,表达式中使用的字面浮点值将被视为双精度值,并且大多数返回浮点值的数学函数都会返回双精度值。如果只使用double,就可以省去很多麻烦和类型转换。

双精度为64,单精度为64 (float)是32位。 double有一个更大的尾数(实数的整数位)。 任何不准确的地方都将在double中减小。