top1编程
← 返回题目
题解

两个小数相乘

1 条题解

  • 0
    @ 2026-8-3 18:46:46

    解题思路

    两个小数相乘,不能直接用浮点数(会丢精度),用高精度做。方法很巧妙:

    1. 先把两个数去掉小数点,当成大整数相乘(高精度乘法)。
    2. 两个数原来小数点后一共有 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