C++ float和double的区别是什么?

C++ float和double的区别是什么?,c++,c,floating-point,precision,C++,C,Floating Point,Precision,我读过关于双精度和单精度的区别。然而,在大多数情况下,float和double似乎可以互换,即使用其中一种似乎不会影响结果。真的是这样吗?浮子和双浮子什么时候可以互换?它们之间有什么区别 双精度是64,单精度 浮点是32位。 double的尾数大于实数的整数位。 任何误差都将在双精度模式下减小。 浮点数的精度低于双精度浮点。虽然您已经知道,但请阅读以便更好地理解。以下是标准C99 ISO-IEC 9899 6.2.5§10或C++2003 ISO-IEC 14882-2003 3.1.9§8标准

我读过关于双精度和单精度的区别。然而,在大多数情况下,float和double似乎可以互换,即使用其中一种似乎不会影响结果。真的是这样吗?浮子和双浮子什么时候可以互换?它们之间有什么区别

双精度是64,单精度 浮点是32位。 double的尾数大于实数的整数位。 任何误差都将在双精度模式下减小。
浮点数的精度低于双精度浮点。虽然您已经知道,但请阅读以便更好地理解。

以下是标准C99 ISO-IEC 9899 6.2.5§10或C++2003 ISO-IEC 14882-2003 3.1.9§8标准的内容:


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

C++标准添加:

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


我建议看一看深入介绍IEEE浮点标准的优秀文章。您将了解表示的详细信息,并将意识到在大小和精度之间存在权衡。浮点表示的精度随着大小的减小而增加,因此-1和1之间的浮点数是精度最高的。

使用浮点数时,您不能相信您的本地测试将与在服务器端执行的测试完全相同。本地系统上的环境和编译器可能不同,最终测试在哪里运行。我以前在一些TopCoder竞赛中多次看到过这个问题,特别是当你试图比较两个浮点数时。

浮点计算中涉及的数字大小不是最相关的。相关的是正在进行的计算

#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;
  }
}
本质上,如果您正在执行一个计算,并且结果是一个无理数或循环小数,那么当该数字被压缩到您正在使用的有限大小数据结构中时,将出现舍入错误。由于double是float大小的两倍,因此舍入误差将小得多

测试可能特别使用会导致此类错误的数字,因此测试表明您在代码中使用了适当的类型。

巨大的差异

顾名思义,a的精度是[1]的2倍。一般来说,双精度有15位小数,而浮点精度有7位

以下是计算位数的方法:

double有52个尾数位+1个隐藏位:log253÷log10=15.95位

浮点有23个尾数位+1个隐藏位:log224÷log10=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

此外,float的最大值约为3e38,而double的最大值约为1.7e308,因此使用float比double更容易达到无穷大,即一个特殊的浮点数,对于一些简单的事情,例如计算60的阶乘

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

当然,有时,即使是double也不够精确,因此我们有时有long double[1]上面的例子在Mac上给出了9.000000000000000066,但所有浮点类型都有舍入错误,因此如果精度非常重要,例如货币处理,则应使用int或分数类

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


(1):C和C++标准没有指定浮点、双和长双的表示。有可能所有三个都实现为IEEE双精度。然而,对于大多数架构,gcc、MSVC;x86,x64,ARM float实际上是一个IEEE单精度浮点数binary32,double是一个IEEE双精度浮点数binary64。

给定一个二次方程: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;
}  
注意数字不是很大,但仍然可以使用float获得取消效果


事实上,上述方法不是使用单精度或双精度浮点数求解二次方程的最佳方法,但即使使用32位长的。

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

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

#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;
  }
}
long double类型名义上是80位,但给定的编译器/操作系统配对可能会将其存储为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.83之后看到的,精度显著下降

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

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

与整数不同,浮点有一个小数点,双精度也有一个小数点。
但两者之间的区别在于,double的详细程度是float的两倍,这意味着它的小数点后的数字量可以是float的两倍。

如果使用嵌入式处理,最终,底层硬件(如FPGA或某些特定处理器/微控制器模型)将在硬件中以最佳方式实现浮点运算,而double将使用软件例程。因此,如果浮点的精度足以满足需要,那么使用float-then-double时,程序的执行速度会快几倍。如其他答案所述,注意累加错误。

有三种浮点类型:

浮动 双重的 长双人 一个简单的维恩图将解释: 类型的值集


求和的一般建议是在求和之前先按最小的大小对浮点数进行排序。请注意,虽然C/C++float和double几乎总是分别为IEEE单精度和双精度,但C/C++long double的变量要大得多,这取决于您的CPU、编译器和操作系统。有时它与double相同,有时它是某些特定于系统的扩展格式,有时它是IEEE quad precision。@R..GitHubSTOPHELPINGICE:为什么?你能解释一下吗?@询问:例如,考虑一个数组,值为2 ^ 24,后面是值1的2 ^ 24重复。按顺序求和产生2^24。反转产生2^25。当然,你可以举出一些例子,例如,用一个累加器重复2^25次,任何一个阶数最终都会出现灾难性的错误,但最小的第一个阶数是最好的。为了做得更好,您需要某种类型的树。@R..GitHubSTOPHELPINGICE:如果数组同时包含正数和负数,求和就更加棘手了。例如,四字节。实际上是浮点数。请确定:解决问题的方法应该是最好使用int?如果要迭代100次,应该使用int而不是double进行计数。这里使用double不是一个好的解决方案。你用int来计数,然后做一个内部乘法来得到你的浮点值。这根本不是这个意思。它实际上意味着整数小数位数的两倍,而且超过了两倍。小数位数和精度之间的关系不是线性的:它取决于值:例如,0.5是精确的,但0.33333不是。是我自己还是链接对其他人不起作用?更新了链接。我相信您已经通过搜索标题找到了该文档。
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