题解
两个小数相乘
1 条题解
-
0
解题思路
两个小数相乘,不能直接用浮点数(会丢精度),用高精度做。方法很巧妙:
- 先把两个数去掉小数点,当成大整数相乘(高精度乘法)。
- 两个数原来小数点后一共有 k 位,那么乘积的小数点就在从右往左数第 k 位。
例如
3456.5 × 1234.5:去掉小数点变34565 × 12345 = 426704925,两个数小数点后各 1 位、共 2 位,所以结果是4267049.25。输出时要注意:整数部分如果都是 0,要保留一个 0(比如
0.5×0.5=0.25);乘积某一位是 0 也要照常输出。参考代码
#include <iostream> using namespace std; char sa[30], sb[30]; int a[30], b[30]; int ans[60]; int main() { cin >> sa >> sb; // 求长度和找到小数点 int la = 0, lb = 0; while (sa[la]) la++; while (sb[lb]) lb++; int pa = 0, pb = 0; while (sa[pa] != '.') pa++; while (sb[pb] != '.') pb++; // 两个数小数点后的位数之和 = 结果的小数位数 int dec = (la - 1 - pa) + (lb - 1 - pb); // 去掉小数点,转成整数数组(个位放最前面) int na = 0, nb = 0; for (int i = la - 1; i >= 0; i--) if (sa[i] != '.') a[na++] = sa[i] - '0'; for (int i = lb - 1; i >= 0; i--) if (sb[i] != '.') b[nb++] = sb[i] - '0'; // 大整数乘法 for (int i = 0; i < na; i++) for (int j = 0; j < nb; j++) ans[i + j] += a[i] * b[j]; int hi = na + nb; for (int i = 0; i < hi; i++) { ans[i + 1] += ans[i] / 10; ans[i] %= 10; } while (ans[hi]) hi++; // 从高到低生成字符串,并在合适位置放小数点 char out[65]; int oi = 0; for (int i = hi - 1; i >= 0; i--) { out[oi++] = char('0' + ans[i]); if (i == dec) out[oi++] = '.'; // 从右往左数dec位放小数点 } out[oi] = 0; // 去掉整数部分的前导0(但保留一个0) int start = 0; while (out[start] == '0' && out[start + 1] != '.') start++; for (int i = start; i < oi; i++) cout << out[i]; return 0; }复杂度分析
设去掉小数点后两个数位数分别为 n、m,乘法两层循环 n×m 次,时间复杂度 O(n×m);额外空间复杂度 O(n+m)。
- 1