C++ 浮点数使用中,核心注意事项是精度误差、格式化输出控制、类型选择与比较方式,具体要点如下:
1. 两种浮点数类型
| 类型 | 关键字 | 精度 | 占用空间 | 记忆口诀 |
|---|---|---|---|---|
| 单精度 | float |
约 6-7 位有效数字 | 4 字节 | 小盒子,装得少 |
| 双精度 | double |
约 15-16 位有效数字 | 8 字节 | 大盒子,装得多 |
建议 :信奥竞赛中,无脑选 double 。float 精度太低,容易踩坑。
2. 最大陷阱:精度误差
浮点数在计算机中是用二进制存储的,很多十进制小数无法被精确表示。
cpp
double a = 0.1 + 0.2;
cout << a << endl; // 输出可能是 0.30000000000000004,而不是 0.3!
后果 :直接用 == 比较两个浮点数,可能会出错。
cpp
double a = 0.1 + 0.2;
if (a == 0.3) {
cout << "相等"; // 这行代码可能不会执行!
}
正确做法:用一个极小的数(叫"容差")来比较:
cpp
double a = 0.1 + 0.2;
if (abs(a - 0.3) < 1e-8) { // 1e-8 就是 0.00000001
cout << "相等";
}
口诀 :浮点数比较,永远不要用 ==,要用"差值小于一个很小的数"来判断。
3. 格式化输出(printf 控制小数位数)
这是信奥竞赛中最常用的技巧:
cpp
double pi = 3.14159265;
printf("%.2f\n", pi); // 保留2位小数,输出 3.14(四舍五入)
printf("%.4f\n", pi); // 保留4位小数,输出 3.1416
printf("%.0f\n", pi); // 保留0位小数,输出 3
注意 :printf 的 %f 默认保留 6 位小数 ,如果题目要求不同位数,一定要用 %.nf 指定。
4. cin/cout 控制小数位数
如果用 cout,需要加 <iomanip> 头文件:
cpp
#include <iomanip>
double pi = 3.14159265;
cout << fixed << setprecision(2) << pi << endl; // 输出 3.14
注意 :fixed 和 setprecision 一旦设置,后面所有的 cout 都会受影响,直到你重新设置。
5. 整数除法 vs 浮点除法
这是孩子们最容易犯的错:
cpp
cout << 7 / 2 << endl; // 输出 3(整数除法,直接砍掉小数)
cout << 7.0 / 2 << endl; // 输出 3.5(浮点除法)
cout << (double)7 / 2 << endl; // 输出 3.5(强制转换)
口诀 :只要有一个操作数是浮点数,结果就是浮点数。两个都是整数,结果就是整数(小数部分直接扔掉)。
6. scanf 和 printf 的占位符
cpp
double x;
scanf("%lf", &x); // 读入 double,注意是 %lf(有个 l)
printf("%f", x); // 输出 double,用 %f 就行(输出时不用加 l)
易错点 :scanf 读 double 用 %lf,printf 输出 double 用 %f。很多孩子在这里搞混。
7. 浮点数的特殊值
cpp
double a = 1.0 / 0.0; // 结果是 inf(无穷大)
double b = 0.0 / 0.0; // 结果是 nan(不是一个数)
在信奥竞赛中,尽量避免除以零。如果不确定,可以先判断分母是否为零。
📌 总结速查表
| 注意事项 | 正确做法 |
|---|---|
| 类型选择 | 统一用 double |
| 比较大小 | 用 abs(a-b) < 1e-8,不用 == |
| 保留小数 | printf("%.nf", x) 或 cout << fixed << setprecision(n) |
| 除法陷阱 | 确保至少一个操作数是浮点数 |
| scanf 读入 | double 用 %lf,float 用 %f |
| 默认输出 | printf 的 %f 默认 6 位小数 |