📄 一句话概括
装小数的变量有三种:float(4 字节,约 7 位有效数字)、double(8 字节,约 15~16 位,默认就用它)、long double(更高精度,很少用)。选型口诀只有一句:拿不准就 double。 另外记住两条老结论:不要用 == 比较浮点数;金额别用浮点(换算成"分"用整数算)。
一、三种实型的对比
| 类型 | 字节 | 有效数字 | 怎么写 | 何时用 |
|---|---|---|---|---|
float |
4 | 约 7 位 | float f = 3.14f;(后缀 f) |
内存吃紧:游戏、嵌入式、超大数据集 |
double |
8 | 约 15~16 位 | double d = 3.14;(默认) |
日常计算、科学计算——首选 |
long double |
10/12/16 | 比 double 更高 | long double x = 3.14L; |
极少数要求超高精度的场合 |
为什么 double 是默认:你写 3.14 这个字面量,编译器默认就当 double 处理。所以:
float f = 3.14; // ⚠ 能过,但多数编译器会警告"从 double 转 float 可能丢精度"
float f = 3.14f; // ✓ 正确写法:后缀告诉编译器"我就是要 float"
double d = 3.14; // ✓ 完全匹配
反过来,整数可以直接赋给实型(自动转成小数):
double d = 5; // d 的值是 5.0,合法
二、"有效数字"是什么意思
浮点数存的是有限位数的近似值。所谓"7 位有效数字",是说前 7 位靠得住,第 8 位起就别信了:
float f = 123456789.0f;
double d = 123456789.0;
cout << setprecision(12);
cout << f << endl; // 123456792.000 ← 后几位已经失真!
cout << d << endl; // 123456789.000 ← 准的
这就是"float 只约 7 位"的实际含义:超过 7 位的数,后面的数字会变成"编"出来的。
📝 一个常见误会
cout 默认只显示 6 位有效数字,所以很多时候 float 和 double 的输出看起来一样——那只是被"四舍五入"遮住了。要看清真相,得用 setprecision(12) 把位数放开(2.5.3 讲)。
三、实型变量的三个实操要点
要点一:输出位数由你控制
cout << 3.14159265358979 << endl; // 默认输出 3.14159(6 位有效数字)
cout << setprecision(10) << 3.14159265358979 << endl; // 3.141592654
要点二:比较不要用 ==(2.2.2 已讲原理,这里给做法)
// ✗ 危险
if (a == b) { ... }
// ✓ 正确:判断"差得够小"
if (fabs(a - b) < 1e-6) { ... } // 1e-6 就是 0.000001
要点三:金额别用浮点
// ✗ 危险:0.1 + 0.2 != 0.3
double money = 0.1 + 0.2;
// ✓ 正确:以"分"为单位用整数
long long moneyFen = 10 + 20; // 30 分
四、动手 Demo:亲手看到 float 的失真
新建 floatvar.cpp:
#include <iostream>
#include <iomanip> // setprecision 在这里
using namespace std;
int main() {
float f = 123456789.0f;
double d = 123456789.0;
cout << setprecision(12); // 放开显示位数
cout << "float = " << f << endl;
cout << "double = " << d << endl;
cout << setprecision(6); // 恢复默认
cout << "默认位数下看起来一样:" << f << " vs " << d << endl;
cout << "float 占 " << sizeof(float) << " 字节" << endl;
cout << "double 占 " << sizeof(double) << " 字节" << endl;
return 0;
}
看到什么算成功:
float = 123456792.000 ← 后两位已经不是原来的数了
double = 123456789.000
默认位数下看起来一样:1.23457e+08 vs 1.23457e+08 ← 被默认 6 位遮住了
这一对比说明两件事:① float 真的会失真;② 默认输出位数会掩盖问题,所以别用"打印出来看着对"来判断精度够不够。
30 秒实验:把 setprecision(12) 换成 setprecision(20),再看 double 的 123456789.0——你会发现它也开始"抖"了(因为 15 位之后同样不可靠)。没有无限精确的浮点。
五、常见误区
- "
float和double差不多,随便选"——差一倍精度。7 位有效数字连"123456789"都存不准;默认用double - "写
float f = 3.14;也没报错,说明没问题"——能过编译,但可能触发精度警告,而且风格上说明你没搞清类型。要float就写3.14f - "打印出来是 3.14,说明存的就是 3.14"——不是,只是显示被截断到 6 位了。要用
setprecision看真实值 - "用
long double就高枕无忧"——它在不同编译器/平台上的字节数不一样(10/12/16 都可能),跨平台时反而不如double稳定
自测四问(点开对答案)
1. `float` / `double` 各占几字节、多少位有效数字?——4 字节约 7 位 / 8 字节约 15~16 位。 2. 写 `float` 变量时该注意什么?——**加后缀 `f`**(`3.14f`),否则编译器可能警告精度丢失。 3. 为什么"打印看着对"不能作为精度够用的证据?——`cout` 默认只显示 **6 位有效数字**,会把后面的失真藏起来。 4. 金额为什么不用浮点?——二进制存不准小数,累加会产生分毫误差。**改用整数"分"**。- ☑ 字符变量