double 是 float 的高精度版本。double 提供了大约两倍的精度和更大的表示范围,但代价是占用更多的内存空间。

(图片来源网络,侵删)
下面我们从几个核心维度进行详细对比。
核心区别对比表
| 特性 | float (单精度浮点数) |
double (双精度浮点数) |
说明 |
|---|---|---|---|
| 关键字 | float |
double |
C 语言中的类型关键字。 |
| 内存大小 | 通常为 4 字节 (32 位) | 通常为 8 字节 (64 位) | double 占用的内存是 float 的两倍。 |
| 精度 | 约 6-9 位有效数字 | 约 15-18 位有效数字 | 这是两者最核心的区别。double 能表示更多的小数位,精度更高。 |
| 表示范围 | 约 ±3.4E-38 到 ±3.4E+38 | 约 ±1.7E-308 到 ±1.7E+308 | double 能表示更大或更小的数值,范围更广。 |
| 默认类型 | 在 C 语言中,14 这样的浮点字面量默认是 double 类型。 |
如果你写 float f = 3.14;,编译器可能会给出警告,因为精度可能丢失。 |
|
| 格式化输出 | %f 或 %e |
%lf 或 %le |
重要: 在 scanf 函数中,读取 double 类型变量必须使用 %lf。printf 中使用 %f 和 %lf 效果相同,但 %lf 是更规范的做法。 |
| 运算速度 | 在某些旧架构或特定硬件上可能比 double 稍快。 |
在现代 CPU 上,由于硬件优化,double 和 float 的运算速度通常没有明显差异。 |
除非在性能极其敏感的嵌入式系统中,否则通常不需要考虑速度问题。 |
深入解析
内存大小与存储格式 (IEEE 754 标准)
float 和 double 在内存中的存储都遵循 IEEE 754 浮点数标准,它们都由三部分组成:
- 符号位: 1 位,决定数字是正数还是负数。
- 指数位: 决定数字的表示范围(即小数点可以移动多远)。
- 尾数位: 决定数字的精度(即有多少位是有效的)。
float (32位) 和 double (64位) 的分配如下:
| 类型 | 总位数 | 符号位 | 指数位 | 尾数位 |
|---|---|---|---|---|
| float | 32 | 1 | 8 | 23 |
| double | 64 | 1 | 11 | 52 |
double的指数位更多 (11 vs 8),所以它的表示范围更大。double的尾数位多得多 (52 vs 23),所以它的精度高得多,尾数位越多,能存储的有效数字就越多,计算时的舍入误差就越小。
精度对比 (最直观的区别)
精度指的是一个浮点数能够表示的有效数字的个数。

(图片来源网络,侵删)
示例代码:
#include <stdio.h>
int main() {
float f_num = 123456789.12345678f; // 注意 f 后缀,表示这是一个 float 字面量
double d_num = 123456789.12345678;
printf("float value: %.10f\n", f_num);
printf("double value: %.10lf\n", d_num);
return 0;
}
可能的输出结果:
float value: 123456792.0000000000 // 精确的 123456789 丢失了,后面的数字都是填充的
double value: 123456789.1234567812 // 保留了更多位,非常接近原始值
分析:
float只有 23 位尾数,无法精确存储12345678这个数,导致精度严重丢失。double有 52 位尾数,能够精确地表示这个数的绝大部分,只存在非常微小的舍入误差。
另一个经典例子:0.1
#include <stdio.h>
int main() {
float f = 0.1f;
double d = 0.1;
printf("float representation of 0.1: %.20f\n", f);
printf("double representation of 0.1: %.20lf\n", d);
return 0;
}
输出结果:
float representation of 0.1: 0.10000000149011611938 // 不精确
double representation of 0.1: 0.10000000000000000555 // 更精确
分析:
在二进制中,0.1 是一个无限循环小数,计算机无法精确表示它,只能存储一个近似值。double 由于精度更高,它的近似值比 float 的近似值更接近真实的 0.1。
代码使用示例与注意事项
字面量后缀
f或F:表示float类型字面量。14f,0F。l或L:表示long double类型字面量。- 默认情况(如
14)是double类型。
scanf 的陷阱 (非常重要!)
这是一个初学者非常容易犯的错误。
#include <stdio.h>
int main() {
float f;
double d;
// 错误示范!
// %lf 用于 double,但这里变量是 float,会导致未定义行为或编译警告
printf("Enter a float: ");
scanf("%lf", &f); // 错误!
// 正确示范
printf("Enter a double: ");
scanf("%lf", &d); // 正确!
// printf 中 %f 和 %lf 都可以,但推荐统一风格
printf("You entered float: %f\n", f);
printf("You entered double: %lf\n", d);
return 0;
}
规则总结:
scanf读取float:使用%f。scanf读取double:必须使用%lf。printf打印float和double:使用%f或%lf都可以,但使用%lf与scanf保持一致是更好的编程习惯。
如何选择?使用场景
什么时候应该使用 float?
- 内存极其紧张:在嵌入式系统、图形学(处理大量顶点坐标)等场景,当内存带宽和容量是首要瓶颈时,使用
float可以节省一半的内存。 - 精度要求不高:表示游戏中的位置、颜色值(RGB/Alpha)等,通常不需要 15 位以上的精度,
float足够。 - 性能敏感:虽然现代 CPU 上差异不大,但在一些特定的 GPU 算法或 DSP(数字信号处理器)中,单精度运算可能被优化得更快。
什么时候应该使用 float?
几乎所有情况下,都应默认使用 double。
- 默认选择:
double是 C/C++ 中浮点类型的“默认”选择,它能提供更高的精度和范围,能满足绝大多数科学计算、金融、工程等领域的需求。 - 避免精度丢失:使用
double可以有效减少因多次运算累积的舍入误差,使结果更可靠。 - 现代硬件优化:64 位 CPU 是主流,硬件对
double运算有很好的优化,性能损失通常可以忽略不计。
总结一下选择策略:
- 不确定用哪个?用
double。 这是最安全、最现代的做法。 - 明确知道内存是瓶颈,且精度要求不高?才考虑用
float。
float |
double |
|
|---|---|---|
| 本质 | 单精度浮点数 | 双精度浮点数 |
| 核心优势 | 占用内存小 | 精度高,范围大 |
| 核心劣势 | 精度低,范围小 | 占用内存是 float 的两倍 |
| 使用建议 | 仅在内存敏感且精度要求不高的场景使用 | 默认选择,适用于绝大多数场景 |
理解 float 和 double 的区别,是写出健壮、可靠数值计算程序的基础。double 是更精确、更强大的版本,并在不确定时优先选择它。
