文章目录
- 💯前言
- 💯题目一:计算成绩
- 问题分析与优化实现
- 优化后的实现优势
- 💯题目二:浮点数向零舍入
- 不同实现方式的比较
- 1. 使用强制类型转换 `(int)`
- 2. 使用标准库函数 `trunc()`
- 整数范围的处理
- 💯小结
💯前言
- 在本次对话中,我们详细讨论了关于 C++编程题目 中的若干关键问题,包括 权重加权的计算、浮点数的处理、
向零舍入
的实现方式,以及如何处理大范围整数
的计算。这些讨论在涉及 基础实现 和 优化 的过程中,不仅探讨了技术实现,还涵盖了相关设计决策的 理论依据。以下内容系统地整理了这次对话的思路和方法,以便完整呈现 解决问题的过程 和背后的逻辑。
C++ 参考手册
💯题目一:计算成绩
计算成绩
题目描述
牛牛最近学习了C++入门课程,这门课程的总成绩计算方法如下:
总成绩 = 作业成绩×20% + 小测成绩×30% + 期末考试成绩×50%
牛牛很想知道,这门课程最后他能得到多少分。
输入格式
输入只有一行,包含三个非负整数,分别表示牛牛的作业成绩、小测成绩和期末考试成绩。每项得分数范围从0到100,且三项成绩满分都是100分。
输出格式
输出只有一行,包含一个整数,表示牛牛的总成绩,满分也是100分。
输入输出样例
示例1
输入:
100 100 80
输出:
90
解释:牛牛的作业成绩是100分,小测成绩是100分,期末考试成绩是80分,总成绩为: 100×20% + 100×30% + 80×50% = 20 + 30 + 40 = 90。
示例2
输入:
60 90 80
输出:
79
解释:牛牛的作业成绩是60分,小测成绩是90分,期末考试成绩是80分,总成绩为: 60×20% + 90×30% + 80×50% = 12 + 27 + 40 = 79。
备注
对于 30% 的数据,A=B=0。
对于另外 30% 的数据,A=B=100。
对于 100% 的数据,0≤A, B, C≤100 且 A, B, C 都是 10 的整数倍。
问题分析与优化实现
- 浮点数运算与整数运算
在初步讨论中,我们首先实现了一个简单的解决方案,即使用浮点数来计算总成绩,代码如下:
#include <iostream>
using namespace std;int main() {int a, b, c;cin >> a >> b >> c;cout << a * 0.2 + b * 0.3 + c * 0.5 << endl;return 0;
}
在上述代码中,我们直接使用浮点数(0.2
,0.3
,0.5
)来进行加权计算,并输出结果。然而,这种实现方式可能存在一个问题,即 浮点数运算带来的精度问题,尤其是在需要严格保证计算结果为 整数 时。
为了消除 浮点数精度 带来的潜在误差,我们对代码进行了优化,将所有计算转换为 整数运算
。具体思路是将权重从浮点数(20%、30%、50%)改为 整数比例(20
、30
、50
),然后在计算完后除以 100
来得到最终结果,代码如下:
#include <iostream>
using namespace std;int main() {int a, b, c;cin >> a >> b >> c;// 使用整数运算,避免浮点数精度问题int total_score = a * 20 + b * 30 + c * 50;total_score /= 100;cout << total_score << endl;return 0;
}
这种 整数运算 的实现不仅更加 高效,而且消除了浮点数运算中由于 二进制表示的限制 而产生的 精度误差,使得计算结果更加 可靠。
- 老师的做法:使用强制类型转换
在课堂上,老师选择了另一种实现方式,即通过将浮点数的计算结果进行强制类型转换来实现。其代码如下:
#include <iostream>
using namespace std;int main() {int a, b, c;cin >> a >> b >> c;// 使用浮点数计算并进行强制类型转换int total_score = (int)(a * 0.2 + b * 0.3 + c * 0.5); // 这里的 (a * 0.2 + b * 0.3 + c * 0.5) 计算结果是 double 类型,表示浮点数运算结果。cout << total_score << endl;return 0;
}
在这种做法中,老师使用了 (int)
强制将浮点数结果转换为整数。这是因为 (a * 0.2 + b * 0.3 + c * 0.5)
的计算结果是 double
类型,即浮点数类型,而通过 (int)
强制类型转换可以将浮点数截断为整数部分(即舍弃小数部分)。这种方法的优点在于代码相对简单,不需要调整权重的表示方式。然而,采用 浮点数计算 加上 强制类型转换 的方式,仍然可能由于 浮点数本身的精度问题 导致不精确的计算结果,特别是在 累积误差较大 的情况下。
优化后的实现优势
-
避免精度问题:
整数运算
避免了浮点数精度不足的问题,确保结果的 准确性。 -
简洁高效:
整数运算
通常比浮点数运算更 高效,尤其是在需要对 大数据量 进行操作时。
💯题目二:浮点数向零舍入
- 浮点数向零舍入
接下来,我们讨论了一个关于浮点数向零舍入的问题。题目要求输入一个双精度浮点数,将其“向零舍入”到最接近的整数。
题目描述
输入一个双精度浮点数,要求将其向零舍入为整数。所谓向零舍入,即对正数向下取整,对负数向上取整。
输入格式
一个双精度浮点数。
输出格式
一个整数,即向零舍入后的结果。
输入输出样例
示例
输入:
2.3
输出:
2
不同实现方式的比较
1. 使用强制类型转换 (int)
在初步实现中,我们使用了 (int)
强制类型转换来实现向零舍入的效果:
#include <iostream>
using namespace std;int main() {double x;cin >> x;int num = (int)x;cout << num << endl;return 0;
}
这种做法将浮点数的小数部分直接截断,对于正数和负数均适用。例如:
- 输入
2.3
,输出2
。 - 输入
-2.3
,输出-2
。
这种实现方式的优点是简单直接,但在表达向零舍入的意图上不够明确。
2. 使用标准库函数 trunc()
为了更清晰地表达向零舍入的意图,我们推荐使用 <cmath>
中的 trunc()
函数:
#include <iostream>
#include <cmath> // 包含 trunc 函数
using namespace std;int main() {double x;cin >> x;long long num = trunc(x);cout << num << endl;return 0;
}
trunc()
函数的作用是对浮点数进行“向零舍入”,无论输入是正数还是负数,结果都与 (int)
转换相同。但使用 trunc()
更加清晰地表达了开发者的意图,使代码的可读性更强。
整数范围的处理
我们还讨论了数据范围的问题。题目要求处理的输入范围可能达到 − 1 0 15 ≤ x ≤ 1 0 15 -10^{15} \leq x \leq 10^{15} −1015≤x≤1015。由于 int
的范围是约 − 2 i m e s 1 0 9 -2 imes 10^9 −2imes109到 2 i m e s 1 0 9 2 imes 10^9 2imes109,显然不足以处理如此大的数字。因此,我们需要使用 long long
类型来存储结果。
修改后的代码如下:
#include <iostream>
using namespace std;int main() {double x;cin >> x;long long num = (long long)x; // 使用 long long 存储结果cout << num << endl;return 0;
}
使用 long long
可以处理范围更大的整数,确保在极端输入情况下不会溢出。
💯小结
在这次对话中,我们通过解决两个 C++编程题,深入探讨了 浮点数运算的精度问题、向零舍入 的不同实现方式,以及 大数范围的处理。以下是关键点总结:
-
加权成绩计算的优化:通过使用
整数运算
代替浮点数运算
,避免 精度问题,简化代码逻辑。 -
向零舍入的实现:可以使用
(int)
强制类型转换实现,也可以使用trunc()
函数,更加清晰地表达意图。 -
数据范围的考虑:当输入数据范围较大时,应使用合适的数据类型,如
long long
,以避免 溢出问题。