「高精度乘法+高精度加法」P10425 [蓝桥杯 2024 省 B] R 格式 题解
解题思路
题意分析:
- 将浮点数乘以 \(2^n\);
- 四舍五入到最接近的整数。
根据题意将 \(d\times 2^n\) 分解为 \(d\times2\times2\times2\times2……\),因为 \(d\) 长度小于等于 \(1024\),所以可以使用高精度乘法的算法来实现
一个小数乘以一个大于 \(0\) 的整数时,小数点位数本身不会改变,但小数点后面的数字可能会发生变化。乘法操作并不改变数字中小数点的位置,它只是会影响小数点前后的数字值。
所以,我们先将小数看作一个整数相乘即可。
四舍五入:最后看小数点第一位是否大于等于 \(5\),如果大于等于 \(5\),前一位需要 \(+1\),需要注意的是这里可能存在连续进位,例如 \(9999.5\) 应该四舍五入为 \(10000\),所以这里应该使用高精度加法的算法
高精度乘法 + 高精度加法
代码大致流程:
- 读取输入的转换参数
n
和浮点数s
。 - 去除
s
中的小数点,并计算出小数点后的位数k
。 - 将处理过的数字转换为一个由单个数字组成的向量
a
,并对其进行n
次乘以 2 的操作。 - 判断是否需要进行四舍五入,根据判断结果输出最终的整数值。
此代码通过数位分离和模拟手算乘法、加法的方式,精确地处理了大数问题,确保了在面对极大的 \(n\) 时仍能正确计算并避免浮点数精度问题。
代码
如果还是不懂的话可以看下代码,很详细。
#include <bits/stdc++.h>
using namespace std;
// 乘法函数,用于将向量 a 中的每个元素乘以整数 n,并返回结果向量
vector<int> mul(vector<int> a, int n) {
vector<int> c; // 结果向量
int t = 0; // 用于累计进位
for (int i = 0; i < a.size() || t; i++) {
if (i < a.size()) t += a[i] * n; // 计算当前位与 n 的乘积加上之前的进位
c.push_back(t % 10); // 将乘积的个位数加入结果向量
t /= 10; // 更新进位
}
return c; // 返回结果向量
}
// 加法函数,用于将向量 b 的每个元素与整数 n 相加,并返回结果向量
vector<int> sum(vector<int> b, int n) {
vector<int> c; // 结果向量
int t = 0; // 用于累计进位
for (int i = 0; i < b.size(); i++) {
t += b[i]; // 加上当前位的值
if (n) t += n % 10; // 如果 n 不为零,则加上 n 的当前位
c.push_back(t % 10); // 将和的个位数加入结果向量
t /= 10; // 更新进位
n /= 10; // 更新 n,移动到下一位
}
if (t) c.push_back(t); // 如果最后还有进位,加到结果向量的末尾
return c; // 返回结果向量
}
int main() {
int n; // 转换参数 n
string s; // 待转换的浮点数 d 作为字符串
cin >> n >> s; // 从输入读取 n 和 s
string t; // 用于存储去掉小数点后的数字字符串
int k = 0; // 小数点后数字的个数
// 移除小数点,并计算 k
for (int i = 0; i < s.size(); i++) {
if (s[i] != '.')
t += s[i];
else
k = i;
}
k = t.size() - k; // 计算小数点后的位数
vector<int> a; // 存储数字的向量,每个元素是一位数字
// 将字符串 t 的数字转换为向量 a
for (int i = t.size() - 1; i >= 0; i--)
a.push_back(t[i] - '0');
// 将 a 乘以 2^n
for (int i = 1; i <= n; i++)
a = mul(a, 2);
reverse(a.begin(), a.end()); // 反转结果向量,以便从最高位开始处理
int p = a[a.size() - k]; // 获取可能需要四舍五入的位
if (p >= 5) { // 如果需要四舍五入
vector<int> b;
// 构造需要增加 1 的向量 b
for (int i = a.size() - 1 - k; i >= 0; i--) {
b.push_back(a[i]);
}
b = sum(b, 1); // 对 b 加 1
for (int i = b.size() - 1; i >= 0; i--)
cout << b[i]; // 输出结果
} else { // 如果不需要四舍五入
for (int i = 0; i < a.size() - k; i++)
cout << a[i]; // 直接输出结果
}
return 0;
}