English 中文(简体)
“float 和 double 有什么区别?”
原标题:What is the difference between float and double?

我已经阅读了关于双精度和单精度之间的差异。但是,在大多数情况下,floatdouble似乎可以互换,即使用其中之一不会影响结果。这是真的吗?何时floats和doubles可以互换?它们之间的区别是什么?

最佳回答

巨大的差异。

顾名思义,doublefloat 精度高两倍[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
", b); // prints 9.000023

while - 当...时候

double a = 1.0 / 81;
double b = 0;
for (int i = 0; i < 729; ++ i)
    b += a;
printf("%.15g
", 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++的标准没有规定floatdoublelong double的表示方式。它们三个都有可能以IEEE双精度的形式实现。然而,在大多数体系结构中(如gcc、MSVC;x86、x64、ARM),float确实是IEEE单精度浮点数(二进制32),而double是IEEE双精度浮点数(二进制64)。

问题回答

这是标准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的浮点数具有最高精度。

给定一个二次方程: x² - 4.0000000 x + 3.9999999 = 0,精确到10位数字的根为,r₁ = 2.000316228 和 r₂ = 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	%.5f
", 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	%.5f
", 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仍然会产生抵消效应。

实际上,使用单精度或双精度浮点数解二次方程的上述方法并不是最佳方法,但哪怕使用更稳定的方法,答案仍然不会改变。

  • A double is 64 and single precision (float) is 32 bits.
  • The double has a bigger mantissa (the integer bits of the real number).
  • Any inaccuracies will be smaller in the 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,这样的问题将不会发生。

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

有三种浮点类型:

  • float
  • double
  • long double

A simple Venn diagram will explain about: The set of values of the types

将此翻译成中文:输入图像描述

参与浮点运算的数字大小并不是最重要的事情,而是正在执行的计算是最重要的。

本质上,如果你正在进行计算,结果是无理数或循环小数,那么当这个数字被压缩到你正在使用的有限大小的数据结构中时,会产生舍入误差。由于double是float的两倍大小,所以舍入误差会小得多。

测试可能会特别使用某些数字,以引发这种类型的错误,从而测试您在代码中使用的适当类型。 (Translated by an AI language model)

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

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

类型long double名义上是80位,但是可能由于对齐目的,特定的编译器/操作系统组合可能将其存储为12-16字节。long double具有指数,其可达到荒谬地巨大,应具有19位数字精度。在其无穷的智慧中,微软限制了long double到8字节,与普通double相同。

一般而言,只有在需要浮点值/变量时才使用double类型。表达式中使用的字面值浮点值默认情况下将被视为double类型,返回浮点值的大部分数学函数也返回double类型。如果您只使用double类型,则可以节省很多头疼和类型转换。

浮点数的精度比双精度浮点数要低。虽然您已经知道了,但阅读关于浮点运算我们应该知道什么可以更好地理解。

使用浮点数时,您不能保证您的本地测试与在服务器端执行的测试完全相同。您的本地系统和最终测试运行的地方可能使用不同的环境和编译器。我之前在一些 TopCoder 比赛中多次遇到这个问题,特别是当您尝试比较两个浮点数时。

内置的比较操作不同,当您比较两个浮点数时,数据类型的差异(即float或double)可能导致不同的结果。

如果一个人从事嵌入式处理工作,最终底层硬件(例如FPGA或某些特定的处理器/微控制器型号)将会在硬件中最优实现浮点,而双精度会使用软件例程。因此,如果浮点的精度足以满足需求,那么使用浮点比使用双精度快几倍。正如其他答案所指出的,要注意累积误差。

量化地说,正如其他答案所指出的那样,差别在于类型double的精度大约是类型float的两倍,范围大约是它的三倍(取决于如何计算)。

但也许更重要的是质量的不同。类型float具有良好的精度,这通常对您所做的任何事情都足够好。另一方面,类型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.

而在float类型和double类型之间不一定不同的东西是执行速度。在今天大多数通用处理器上,float类型和double类型的算术运算需要大致相同的时间。一切都是并行完成的,因此您不需要因double类型的更大范围和精度而付出速度惩罚。这就是为什么安全地建议您几乎从不使用float类型:使用double类型不应该在速度上花费您任何东西,在空间上它也不应该花费您很多,而且它几乎肯定会在解决精度和舍入误差问题方面有很好的收益。

(尽管如此,但你可能需要的“特殊需求”之一,是你重新对缩微控制器进行嵌入式工作,或为万国邮联优化的书写代码。) 在这些处理器上,<代码>杜布尔可大大放慢,或实际上不存在,因此,在这些情况下,方案人员通常选择速度的<代码>float,并且可能要准确支付。

Unlike an int (whole number), a float have a decimal point, and so can a double. But the difference between the two is that a double is twice as detailed as a float, meaning that it can have double the amount of numbers after the decimal point.





相关问题
Undefined reference

I m getting this linker error. I know a way around it, but it s bugging me because another part of the project s linking fine and it s designed almost identically. First, I have namespace LCD. Then I ...

C++ Equivalent of Tidy

Is there an equivalent to tidy for HTML code for C++? I have searched on the internet, but I find nothing but C++ wrappers for tidy, etc... I think the keyword tidy is what has me hung up. I am ...

Template Classes in C++ ... a required skill set?

I m new to C++ and am wondering how much time I should invest in learning how to implement template classes. Are they widely used in industry, or is this something I should move through quickly?

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

typedef ing STL wstring

Why is it when i do the following i get errors when relating to with wchar_t? namespace Foo { typedef std::wstring String; } Now i declare all my strings as Foo::String through out the program, ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

Window iconification status via Xlib

Is it possible to check with the means of pure X11/Xlib only whether the given window is iconified/minimized, and, if it is, how?

热门标签