提问人:VaioIsBorn 提问时间:3/5/2010 最后编辑:TheMasterVaioIsBorn 更新时间:8/2/2023 访问量:1174528
float 和 double 有什么区别?
What is the difference between float and double?
问:
我读过双精度和单精度之间的区别。然而,在大多数情况下,并且似乎是可以互换的,即使用一个或另一个似乎不会影响结果。真的是这样吗?浮子和双打什么时候可以互换?它们之间有什么区别?float
double
答:
- 双精度是 64,单精度 (float) 为 32 位。
- double 有一个更大的尾数(实数的整数位)。
- 任何不准确之处在双精度中都会更小。
浮点数的精度低于双精度数。虽然您已经知道,但请阅读我们应该了解的浮点运算知识以更好地理解。
评论
以下是标准 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 之间的浮点数是精度最高的浮点数。
使用浮点数时,您不能相信本地测试将与在服务器端完成的测试完全相同。环境和编译器在本地系统上以及运行最终测试的位置可能不同。我之前在一些 TopCoder 比赛中多次看到过这个问题,尤其是当您尝试比较两个浮点数时。
浮点计算中涉及的数字的大小并不是最相关的。正在执行的计算才是相关的。
从本质上讲,如果你正在执行计算,并且结果是一个无理数或重复的小数,那么当该数字被压缩到你使用的有限大小的数据结构中时,就会出现舍入错误。由于 double 的大小是浮点数的两倍,因此舍入误差会小得多。
测试可能专门使用会导致此类错误的数字,因此测试了您在代码中是否使用了适当的类型。
巨大的差异。
顾名思义,双精度
是浮点
数的 2 倍[1]。通常,a 有 15 位十进制精度,而有 7 位。double
float
以下是位数的计算方法:
double
有 52 个尾数位 + 1 个隐藏位:log(253)÷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
此外,浮点数的最大值约为 ,但双精度约为 ,因此使用可以达到“无穷大”(即一个特殊的浮点数)比计算 60 的阶乘更容易得多。3e38
1.7e308
float
double
在测试期间,也许一些测试用例包含这些巨大的数字,如果您使用浮点数,这可能会导致程序失败。
当然,有时甚至不够准确,因此我们有时会有 [1](上面的例子在 Mac 上给出了 9.00000000000000000066),但所有浮点类型都存在舍入误差,因此如果精度非常重要(例如货币处理),您应该使用分数类或分数类。double
long double
int
此外,不要使用对大量浮点数求和,因为误差会迅速累积。如果您使用的是 Python,请使用 .否则,请尝试实现 Kahan 求和算法。+=
fsum
[1]:C 和 C++ 标准没有指定浮点
数、双精度
和长双精度
的表示形式。这三者都有可能实现为IEEE双精度。然而,对于大多数体系结构(gcc、MSVC、x86、x64、ARM),浮点数确实是 IEEE 单精度浮点数 (binary32),而 double
是 IEEE 双精度浮点数
(binary64)。
评论
给定二次方程:x 2 − 4.0000000 x + 3.9999999 = 0,10 位有效数字的精确根为 r 1 = 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
(事实上,以上并不是使用单精度或双精度浮点数求解二次方程的最佳方法,但即使使用更稳定的方法,答案也不会改变。
类型 float,长 32 位,精度为 7 位。虽然它可以存储范围非常大或非常小的值(+/- 3.4 * 10^38 或 * 10^-38),但它只有 7 位有效数字。
double 型,长 64 位,范围更大 (*10^+/-308) 和 15 位精度。
type long double 名义上为 80 位,但给定的编译器/操作系统配对可能会将其存储为 12-16 字节以进行对齐。长双精度有一个大得离谱的指数,应该有 19 位精度。Microsoft 以其无限的智慧,将长双精度限制为 8 个字节,与普通双精度相同。
一般来说,当您需要浮点值/变量时,只需使用类型 double。默认情况下,表达式中使用的文本浮点值将被视为双精度值,并且返回浮点值的大多数数学函数都返回双精度值。如果您只使用 double,您将为自己省去许多麻烦和排版。
评论
内置的比较操作不同,因为当您将 2 个数字与浮点数进行比较时,数据类型的差异(即浮点数或双精度数)可能会导致不同的结果。
我刚刚遇到了一个错误,我花了很长时间才弄清楚,并且可能给你一个很好的浮点精度例子。
#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
int
与(整数)不同,a 具有小数点,.
但两者的区别在于 a 是 a 的两倍,这意味着它在小数点后可以有两倍的数字。int
float
double
double
float
评论
如果使用嵌入式处理,最终底层硬件(例如FPGA或某些特定的处理器/微控制器模型)将在硬件中以最佳方式实现浮点,而double将使用软件例程。因此,如果浮点数的精度足以满足需求,则程序的执行速度将提高浮点数的几倍,然后加倍。正如其他答案中所指出的,要注意累积错误。
有三种浮点类型:
- 浮
- 双
- 长双人房 (Long T
一个简单的维恩图将解释: 类型的值集
从定量上讲,正如其他答案所指出的那样,区别在于类型具有大约两倍的精度和三倍的范围(取决于您的计数方式)。double
float
但也许更重要的是质的差异。类型具有良好的精度,这通常足以满足您正在执行的任何操作。类型 ,另一方面,具有出色的精度,无论您在做什么,几乎总是足够好。float
double
结果,远不如它应该的那样广为人知,是你几乎应该总是使用double
类型。除非你有一些特别特殊的需要,否则你几乎不应该使用类型。float
众所周知,在进行浮点工作时,“舍入误差”通常是一个问题。舍入误差可能很微妙,难以追踪,也难以修复。大多数程序员没有时间或专业知识来追踪和修复浮点算法中的数值错误——因为不幸的是,每个不同算法的细节最终都是不同的。但是类型具有足够的精度,因此在大多数时候,您不必担心。
无论如何,你都会得到好的结果。另一方面,对于类型,四舍五入的令人担忧的问题总是会出现。double
float
类型和执行速度之间不一定有区别。在当今的大多数通用处理器上,对类型和进行算术运算所需的时间或多或少完全相同。一切都是并行完成的,因此您无需为更大的范围和精度而付出速度损失。这就是为什么可以安全地提出你几乎不应该使用类型的建议:使用不应该在速度上花费你任何东西,它不应该在空间上花费你太多,而且它几乎肯定会在摆脱精度和舍入误差问题方面获得丰厚的回报。float
double
float
double
double
float
double
(话虽如此,您可能需要类型的“特殊需求”之一是当您在微控制器上执行嵌入式工作或编写针对 GPU 优化的代码时。在这些处理器上,类型可能明显变慢,或者几乎不存在,因此在这些情况下,程序员通常会选择类型来提高速度,并且可能会为精确度付费。float
double
float
评论