适用对象: 完成了第 6 课(数组)的同学 使用方式: 自学讲义。放在电脑旁边,边读边照着做 学完本课,你应该能:
7 / 2 的结果是 3 而不是 3.5double 存小数,并让除法算出正确的小数结果遇到问题怎么办: 前面六节课我们只用过
int,它只能装整数。今天要还两笔账:第 2
课说过"除不尽以后学",第 6
课说过"求平均数要用小数,以后学"。今天一起还清。
打开上节课的
t2.cpp(求一串数的总和),重新运行一遍。输入 5
和 3 1 4 1 5,应该输出 14。
跑通了就好。现在换个问题:这 5 个数的平均数是多少?
平均数就是总和除以个数,也就是 14 / 5。拿计算器一按,是
2.8。
那就写个程序算算看:
#include <bits/stdc++.h>
using namespace std;
int main() {
int sum = 14;
int n = 5;
cout << sum / n << endl;
return 0;
}运行结果是——
2
不是 2.8,是 2。小数点后面那个 8 不见了。
这就是今天要解决的问题。
先看清楚这个现象。运行下面这个程序:
#include <bits/stdc++.h>
using namespace std;
int main() {
cout << 7 / 2 << endl;
cout << 9 / 4 << endl;
cout << 1 / 3 << endl;
return 0;
}输出:
3
2
0
7 除以 2 应该是 3.5,它给了 3;9 除以 4 应该是 2.25,它给了 2;1 除以 3 应该是 0.333…,它直接给了 0。
⚠️ 两个整数相除,结果也是整数。小数部分不是四舍五入,是直接扔掉。 7 / 2 = 3.5,扔掉 .5,得 3;9 / 4 = 2.25,扔掉 .25,得 2。哪怕是 2.99,扔掉之后也只剩 2。
为什么会这样?因为 7 和 2
都是整数,C++
觉得"你给我两个整数,那我还你一个整数"。它压根就没打算算出小数来。
📝 这不是 bug,是 C++ 故意的。 第 3 课学的
% 求余数就靠这个规矩:7 / 2 得
3(商),7 % 2 得 1(余数),3 × 2 + 1 = 7,正好对上。
那想要 3.5 该怎么办?得先有一种能装小数的盒子。
double:能装小数的盒子(20 分钟)前面六课,我们造盒子只用过一个词:int。
int a = 5; // 装整数的盒子今天认识第二种盒子:double,装小数的盒子。
double x = 3.5; // 装小数的盒子用法和 int 一模一样——能存、能取、能算、能
cin 读进来、能 cout 打出去:
#include <bits/stdc++.h>
using namespace std;
int main() {
double x = 3.5;
double y = 2.0;
cout << x << endl;
cout << x + y << endl;
cout << x * y << endl;
return 0;
}输出:
3.5
5.5
7
📝 double
这个名字不用去想它的意思,就当它是"小数盒子"的代号,跟
int 是"整数盒子"的代号一样。
光把结果存进 double
是没用的。看这个:
#include <bits/stdc++.h>
using namespace std;
int main() {
double ans = 7 / 2; // 想要 3.5
cout << ans << endl;
return 0;
}输出还是:
3
⚠️ 因为 C++ 是先算等号右边、再往左边的盒子里放。
右边的 7 / 2 是两个整数相除,当场就算成了
3,小数部分那时候就已经扔掉了。等它进到 double
盒子里,早就没救了——盒子再能装小数,装进来的也只是个 3。
真正的办法:让参与除法的两个数里,至少有一个是小数。
#include <bits/stdc++.h>
using namespace std;
int main() {
cout << 7 / 2 << endl; // 两个都是整数 → 3
cout << 7.0 / 2 << endl; // 左边是小数 → 3.5
cout << 7 / 2.0 << endl; // 右边是小数 → 3.5
return 0;
}输出:
3
3.5
3.5
📝 7 和 7.0 在 C++
眼里是两样东西。 多写一个
.0,它就从整数变成了小数,除法的规矩也跟着变了。
上面那招是数字写死的情况。可要是像热身那样,除号两边都是变量
sum 和 n,总不能在变量后面加 .0
吧?
办法是:先乘以 1.0。
#include <bits/stdc++.h>
using namespace std;
int main() {
int sum = 14;
int n = 5;
cout << sum * 1.0 / n << endl;
return 0;
}输出:
2.8
成了。sum * 1.0 的意思是"把 sum 乘以
1,值一点没变,但它现在是个小数了",接下来的除法自然就按小数算。
⚠️ * 1.0 必须写在除号前面。 写成
sum / n * 1.0 就完蛋了——C++ 从左往右算,先做
sum / n 得到整数 2,再乘 1.0 变成
2.0,小数部分早在第一步就丢了。
📝 记死这个套路:sum * 1.0 / n。 先乘
1.0,再除。
新建
check1.cpp,把下面三行都输出出来,亲眼看看区别:
5 / 2
5.0 / 2
5 / 2.0
答案应该是 2、2.5、2.5。
小数能算出来了,但输出的样子还不太听话。试试这个:
#include <bits/stdc++.h>
using namespace std;
int main() {
cout << 1 * 1.0 / 3 << endl;
return 0;
}输出:
0.333333
一口气六位。要是题目只要两位怎么办?
在 cout 前面加一句咒语:
#include <bits/stdc++.h>
using namespace std;
int main() {
cout << fixed << setprecision(2); // ← 咒语,写一次就够
cout << 1 * 1.0 / 3 << endl;
cout << 2 * 1.0 / 3 << endl;
cout << 14 * 1.0 / 5 << endl;
return 0;
}输出:
0.33
0.67
2.80
三件事值得注意:
0.67——它是四舍五入的(0.666… 进位成
0.67),不是砍掉。输出的时候会四舍五入,但整数除法是砍掉,两回事,别搞混。2.80——末尾的 0 会补齐,两位就是两位。cout
都听它的,不用每行都写。📝 要保留几位就把括号里的数字改成几。 保留一位写
setprecision(1),保留三位写
setprecision(3)。
⚠️ fixed 不能漏。 只写
setprecision(2) 不写
fixed,它数的就不是小数点后面的位数了,2.8
会被打成 2.8、82.2 会被打成
82——完全不是你要的。两个词一起写,当成一句话背下来。
新建 check2.cpp,用上面的咒语,把
10 * 1.0 / 3 保留两位输出。答案应该是
3.33。
现在把上节课的数组和今天的小数合起来,做第 6 课欠下的那道题。
读入 n 个成绩,求平均分,保留两位小数:
#include <bits/stdc++.h>
using namespace std;
int a[105];
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) cin >> a[i];
int sum = 0; // 老套路:先求总和
for (int i = 0; i < n; i++) sum = sum + a[i];
cout << fixed << setprecision(2);
cout << sum * 1.0 / n << endl; // 再除以个数
return 0;
}输入 5 和 90 85 78 92 66,输出:
82.20
拿计算器验一下:90 + 85 + 78 + 92 + 66 = 411,411 ÷ 5 = 82.2。对上了。
📝 注意成绩本身还是 int。
成绩都是整数,没必要改成
double;只有除出来的那个结果才是小数。今天的新东西只用在最后一行。
错误 1:以为盒子是 double
就万事大吉(本课头号错误)
int sum = 411;
int n = 5;
double avg = sum / n; ← 右边两个整数,当场算成 82
cout << fixed << setprecision(2) << avg << endl;
输出 82.00。
这个错误最阴险:编译器一声不吭,程序照常运行,还煞有介事地给你打了两位小数——只不过小数点后面永远是
00。
📝 看见 .00
结尾的平均分,第一反应就是去检查除号那一行有没有
* 1.0。
错误 2:忘了写 fixed
cout << setprecision(2); ← 漏了 fixed
cout << 82 * 1.0 / 5 << endl;
输出 16 而不是 16.40。
没有 fixed 的时候,setprecision(2)
数的是整个数字一共几位,不是小数点后面几位。数字一大还会变成
1.23457e+06 这种看不懂的样子。
📝 fixed << setprecision(2)
是一句话,不是两句话。 少一个词,输出就面目全非。
⭐ 基础题 1:两个数的平均数(文件名
t1.cpp)
输入两个整数,输出它们的平均数,保留两位小数。
输入样例:
7 2
输出样例:
4.50
#include <bits/stdc++.h>
using namespace std;
int main() {
int a, b;
cin >> a >> b;
cout << fixed << setprecision(2);
cout << (a + b) * 1.0 / 2 << endl;
return 0;
}⚠️ (a + b) 的括号不能省。写成
a + b * 1.0 / 2 的话,C++ 会先算
b * 1.0 / 2(先乘除后加减,跟数学课一样),结果变成 7 + 1 =
8,全错。
⭐⭐ 实战题 2:求平均分(文件名
t2.cpp)
先输入一个整数 n,再输入 n 个整数成绩,输出平均分,保留两位小数。
输入样例:
5
90 85 78 92 66
输出样例:
82.20
#include <bits/stdc++.h>
using namespace std;
int a[105];
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) cin >> a[i];
int sum = 0;
for (int i = 0; i < n; i++) sum = sum + a[i];
cout << fixed << setprecision(2);
cout << sum * 1.0 / n << endl;
return 0;
}和讲义第 5
节一模一样,这题就是让你亲手再敲一遍。敲完对照一下,看有没有把
* 1.0 漏掉。
⭐⭐⭐ 冲刺题 3:几个人高于平均分(文件名
t3.cpp)
先输入一个整数 n,再输入 n 个整数成绩。输出平均分(保留两位小数),以及有几个人的成绩高于平均分。
输入样例:
5
90 85 78 92 66
输出样例:
平均分是 82.20
高于平均分的有 3 人
#include <bits/stdc++.h>
using namespace std;
int a[105];
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) cin >> a[i];
int sum = 0;
for (int i = 0; i < n; i++) sum = sum + a[i];
double avg = sum * 1.0 / n; // 先把平均分存起来
int cnt = 0; // 计数器清零
for (int i = 0; i < n; i++) { // 再从头把数组走一遍
if (a[i] > avg) cnt++;
}
cout << fixed << setprecision(2);
cout << "平均分是 " << avg << endl;
cout << "高于平均分的有 " << cnt << " 人" << endl;
return 0;
}这题的关键是数组要走两遍:第一遍不走完就不知道平均分是多少,知道了平均分才能开始第二遍数人头。这也正是上节课说的"先存进数组"的好处——数还在盒子里,想走几遍就走几遍。
⚠️ 别把 double avg 写成 int avg。写成
int 的话 82.2 会被砍成 82,而 78
这些正好卡在中间的成绩就可能数错。
| 写法 | 意思 |
|---|---|
double x; |
造一个能装小数的盒子 |
double x = 3.5; |
造盒子并装进 3.5 |
cin >> x; |
读一个小数进去(和 int 一样用) |
7 / 2 |
两个整数相除 → 3,小数被扔掉 |
7.0 / 2 |
有一边是小数 → 3.5 |
sum * 1.0 / n |
变量相除要小数结果,就这么写 |
cout << fixed << setprecision(2); |
从这行起,所有小数都按两位输出 |
必背套路:
求平均数: cout << fixed << setprecision(2);
cout << sum * 1.0 / n << endl;
保留 n 位: setprecision(n),前面的 fixed 不能漏
易错点:
| 症状 | 原因 |
|---|---|
平均分永远是 .00 结尾 |
除号两边都是整数,忘了 * 1.0 |
| 结果比正确答案小一点,还是个整数 | double avg = sum / n; 右边先按整数算完了 |
输出 16 而不是 16.40 |
只写了 setprecision,漏了 fixed |
输出变成 1.23457e+06 |
同上,漏了 fixed |
a + b * 1.0 / 2 算出来不对 |
忘了加括号,先乘除后加减 |
以后学:
把一串数从小到大排序、二维数组(表格)、字符串、(double)
这种更正规的转换写法、小数的精度问题(两个小数不能直接用 ==
比是否相等)。
9 / 4 和 9.0 / 4
分别是多少,以及为什么不一样double avg = sum / n; 救不回小数sum * 1.0 / n 改成 sum / n
跑一遍,亲眼看看 82.20 变成 82.00fixed 删掉跑一遍,看看输出变成什么样