🔷 第二章 C++语言基础
📄 一句话概括

装小数的变量有三种: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 位之后同样不可靠)。没有无限精确的浮点。

五、常见误区

  1. "float 和 double 差不多,随便选"——差一倍精度。7 位有效数字连"123456789"都存不准;默认用 double
  2. "写 float f = 3.14; 也没报错,说明没问题"——能过编译,但可能触发精度警告,而且风格上说明你没搞清类型。要 float 就写 3.14f
  3. "打印出来是 3.14,说明存的就是 3.14"——不是,只是显示被截断到 6 位了。要用 setprecision 看真实值
  4. "用 long double 就高枕无忧"——它在不同编译器/平台上的字节数不一样(10/12/16 都可能),跨平台时反而不如 double 稳定
自测四问(点开对答案) 1. `float` / `double` 各占几字节、多少位有效数字?——4 字节约 7 位 / 8 字节约 15~16 位。 2. 写 `float` 变量时该注意什么?——**加后缀 `f`**(`3.14f`),否则编译器可能警告精度丢失。 3. 为什么"打印看着对"不能作为精度够用的证据?——`cout` 默认只显示 **6 位有效数字**,会把后面的失真藏起来。 4. 金额为什么不用浮点?——二进制存不准小数,累加会产生分毫误差。**改用整数"分"**。

相关笔记