float和double有什么区别?

Vai*_*orn 384 c c++ floating-point precision

我已经读过双精度和单精度之间的区别.然而,在大多数情况下,floatdouble,似乎可以用一个可以互换的,即或其他的似乎不影响使用效果.这是真的吗?浮动和双打什么时候可以互换?它们之间有什么区别?

ken*_*ytm 477

巨大的差异.

顾名思义,a double的精度为[1]的 2倍.一般来说,a 有15个十进制数字的精度,而有7个.floatdoublefloat

以下是计算位数的方式:

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
Run Code Online (Sandbox Code Playgroud)

double a = 1.0 / 81;
double b = 0;
for (int i = 0; i < 729; ++ i)
    b += a;
printf("%.15g\n", b); // prints 8.99999999999996
Run Code Online (Sandbox Code Playgroud)

此外,float的最大值是大约3e38,但是double是大约1.7e308,所以使用float可以比double简单的东西更容易点击"无穷大"(即特殊的浮点数),例如计算60的阶乘.

在测试期间,可能有一些测试用例包含这些巨大的数字,如果您使用浮点数,可能会导致程序失败.


当然,有时甚至double不够准确,因此我们有时会long double[1](上面的例子在Mac上给出9.000000000000000066),但是所有浮点类型都有四舍五入的错误,所以如果精度非常重要(例如钱)处理)你应该使用int或分数类.


此外,不要使用+=大量浮点数,因为错误会很快累积.如果您使用的是Python,请使用fsum.否则,尝试实现Kahan求和算法.


[1]:C和C++标准没有规定的表示float,doublelong double.所有这三个都可以实现为IEEE双精度.然而,对于大多数的架构(GCC,MSVC; 86,64,ARM)float 确实是一个IEEE单精度浮点数(binary32),并且double 一个IEEE双精度浮点数(binary64).

  • 求和的通常建议是在求和之前按幅度(最小的第一个)对浮点数进行排序. (7认同)
  • 请注意,虽然 C/C++ float 和 double 几乎总是分别为 IEEE 单精度和双精度,但 C/C++ long double 的变量要大得多,具体取决于您的 CPU、编译器和操作系统。有时它与双精度相同,有时它是某些特定于系统的扩展格式,有时它是 IEEE 四精度。 (2认同)
  • @InQusitive:例如,考虑一个由值 2^24 和值 1 的 2^24 次重复组成的数组。按顺序求和会产生 2^24。反转产生 2^25。当然,您可以举一些例子(例如,将 1 重复 2^25 次),其中任何顺序最终都会因单个累加器而出现灾难性错误,但最小量值优先是其中最好的。为了做得更好,你需要某种树。 (2认同)
  • @R..GitHubSTOPHELPINGICE:如果数组同时包含正数和负数,求和会更加棘手。 (2认同)

Gre*_*osz 54

这是标准C99(ISO-IEC 98996.2.5§10)或C++ 2003(ISO-IEC 14882-20033.1.9§8)标准所说的:

有三种浮点类型:float,double,和long double.该类型double提供至少与其一样多的精度float,并且该类型long double提供至少与其一样多的精度double.该类型的值float集是该类型的值集的子集double; 类型的值double集是该类型的值集的子集long double.

C++标准增加了:

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

我建议看看优秀的每个计算机科学家应该知道的关于浮点算术的内容,该算法深入涵盖了IEEE浮点标准.您将了解表示细节,并且您将意识到在幅度和精度之间存在权衡.随着幅度减小,浮点表示的精度增加,因此-1和1之间的浮点数是具有最高精度的浮点数.


Alo*_*hal 26

给定二次方程:x 2  - 4.0000000  x  + 3.9999999 = 0,精确根到10位有效数字,r 1  = 2.000316228,r 2  = 1.999683772.

使用floatdouble,我们可以写一个测试程序:

#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;
}  
Run Code Online (Sandbox Code Playgroud)

运行程序给了我:

2.00000 2.00000
2.00032 1.99968
Run Code Online (Sandbox Code Playgroud)

请注意,数字并不大,但仍然可以使用取消效果float.

(事实上​​,上述不是使用单精度或双精度浮点数求解二次方程的最佳方法,但即使使用更稳定的方法,答案也保持不变.)


gra*_*eds 19

  • 双精度为64,单精度(浮点数)为32位.
  • double有一个更大的尾数(实数的整数位).
  • 双倍的任何不准确性都会更小.


Dol*_*lbz 12

浮点计算中涉及的数字大小并不是最相关的.这是正在执行的相关计算.

本质上,如果您正在执行计算并且结果是无理数或重复的小数,那么当该数被压缩到您正在使用的有限大小数据结构时,将存在舍入误差.由于double是float的两倍,因此舍入误差会小很多.

测试可能会专门使用会导致此类错误的数字,因此测试您在代码中使用了适当的类型.


Zai*_*Ali 9

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

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

类型long double名义上是80位,但是给定的编译器/ OS配对可以将其存储为12-16个字节以用于对齐目的.long double有一个非常庞大的指数,应该有19位数的精度.微软凭借其无限的智慧,将长双倍限制为8字节,与普通双重相同.

一般来说,只需在需要浮点值/变量时使用double类型.默认情况下,表达式中使用的文字浮点值将被视为双精度值,并且返回浮点值的大多数数学函数都会返回双精度值.如果你只使用双倍,你将节省许多头痛和类型.


N 1*_*1.1 8

浮点数的精度低于双精度数.虽然您已经知道,但请阅读我们应该了解的关于浮点运算的内容以便更好地理解.

  • 不,在C和C++中,浮点数和双精度数可以具有完全相同的精度.这取决于实现.例如,参见[Gregory Pakosz的回答](http://stackoverflow.com/questions/2386772/difference-between-float-and-double/2386808#2386808). (3认同)

Ell*_*ang 7

我刚遇到一个错误,让我永远弄明白,并且可能会给你一个漂浮精度的好例子.

#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;
  }
}
Run Code Online (Sandbox Code Playgroud)

输出是

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
Run Code Online (Sandbox Code Playgroud)

正如您在0.83之后看到的那样,精度显着下降.

但是,如果我设置t为double,则不会发生这样的问题.

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

  • 在这里使用`double`不是一个好的解决方案.你使用`int`来计算并进行内部乘法来得到你的浮点值. (7认同)
  • 只是为了确定:你的问题的解决方案应该是使用int优选?如果要迭代100次,则应使用int而不是使用double (4认同)

Anu*_*mar 6

有三种浮点类型:

  • 漂浮
  • 双倍的
  • 长双

一个简单的维恩图将解释:类型的值集

在此处输入图片说明