C++大数问题

此文参考自:https://blog.csdn.net/hacker00011000/article/details/51298294
他的快排也很好:三种快排四种优化
这里暂时有大数加法、大数减法、大数阶乘,其他的以后补上:
https://blog.csdn.net/y990041769/article/details/20116995

  1. 大数相加
    1、从结尾开始每位相加
    2、两个整数长度不相等(肯定有一个已经加完了,再把没有加完的加上去)
    3、最高位有进位,要再进一位
    4、结果字符串逆序

  2. 大数相乘
    分析
    12*34=?
    乘数:12
    被乘数:34
    1、先把乘数列出来,第i行列左起第i位数,列N次(N为乘数的位数)
    第二行起每次右移一位

(1) (1)
    (2) (2)

2、写入被乘数,按先列后行的方式

(1,3) (1,4)
      (2,3) (2,4)

3、将()内的数两乘

(1,3=3) (1,4=4)
        (2,3=6) (2,4=8)

4、相加,注意进位

(1,3=3) (1,4=4)
 (2,3=6) (2,4=8) -------------------------
 3 10 8
 . -------------------------
 4 0 8

12*34=408

再看三位数乘法
123*456=?
第一步:

(1) (1) (1)
    (2) (2) (2)
        (3) (3) (3) 

第二步:

(1,4) (1,5) (1,6)
      (2,4) (2,5) (2,6)
            (3,4) (3,5) (3,6)

第三步:

(1,4= 4) (1,5= 5) (1,6= 6)
         (2,4= 8) (2,5=10) (2,6=12)
                  (3,4=12) (3,5=15) (3,6=18)

第四步:

(1,4= 4) (1,5= 5) (1,6= 6)
 (2,4= 8) (2,5=10) (2,6=12)
 (3,4=12) (3,5=15) (3,6=18) ----------------------------------------------
 4 13 28 27 18
 . . . . ----------------------------------------------
 5 6 0 8 8 

123*456=56088
分析一下每一位的值是如何计算出来的,以下说的位都是从个位算起:

结果的第i位,是乘数的第i位乘以被乘数的1位,再加上乘数的第i-1位乘以被乘数的第2位,一起加到乘数的第1位乘以被乘数的第i位。
这样描述起来有点不明白,画个图就很清楚了:
123*456的第3位:从乘数的第3位(1)起到第1位(3),按从右向左的方式
逐个乘以被乘数:
1*6+2*5+3*4=28
再把进位加上就可以了。
即:计算结果的第i位(权值肯定为i,第1位也就是个位权值为0(pow(10, 0)))。等于乘数的第(i~0)位分别与被乘数的第(0~i)位相乘,因为这样每位相乘之后权值仍为i 。然后相加再加上前一位的进位,就是结果的第i位
到这里,已经可以得出一个通用的计算方法,把结果逐位计算出来。
通过上面的分析,我们知道了算法的核心思想,接下来就能把算法实现

#include <iostream>
#include <sstream>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;

//C++大数相加
string BigNumAdd(const string& strNum1, const string& strNum2)
{
    string strSum;
    int len1 = strNum1.size()-1;
    int len2 = strNum2.size()-1;
    int bit = 0;                //保存进位

    //从结尾开始每位相加 
    while (len1>=0 && len2>=0)
    {
        //求每位的和(要把进位也加上) 
        int tmpSum = strNum1[len1]-'0' + strNum2[len2]-'0' + bit;
        //保存进结果 
        strSum += tmpSum % 10 + '0';
        //求进位 
        bit = tmpSum / 10;
        --len1;
        --len2; 
    }

    //两个整数长度不相等(肯定有一个已经加完了,不需要再额外加if来判断,因为while就可以判断)
    while (len1 >= 0)
    {
        //和上个while循环一样
        int tmpSum = strNum1[len1]-'0' + bit;
        strSum += tmpSum % 10 + '0';
        bit = tmpSum / 10;
        --len1; 
    }
    while (len2 >= 0) 
    {
        //和上个while循环一样
        int tmpSum = strNum2[len2]-'0' + bit;
        strSum += tmpSum % 10 + '0';
        bit = tmpSum / 10;
        --len2; 
    }

    //最高位有进位
    if (bit != 0)
        strSum += bit + '0'; 

    //反转
    reverse(strSum.begin(), strSum.end()); 

    return strSum;
}

//C++大数相乘
string BigNumMultiply(const string& strNum1, const string& strNum2)
{
    string strMultiply;
    //两数相乘最大有m+n位
    int bit = 0;
    int len1 = strNum1.size()-1;
    int len2 = strNum2.size()-1;

    //计算每一位 
    for (int i=0; i<len1+len2+2; ++i)
    {
        //计算结果的第i位(权值肯定为i,第1位也就是个位权值为0(pow(10, 0))) 
        //等于乘数的第(i~0)位分别与被乘数的第(0~i)位相乘,因为这样每位相乘之后权值仍为i 
        //然后相加再加上前一位的进位,就是结果的第i位
        //然后%10得出第i位,/10得到进位
        int tmp = 0;
        for (int j=i; j>=0; --j)
        {
            //如果下标超出字符串的范围 j为num1的下标, i-j为num2的下标,然后两数相乘 
            if (j>len1 || (i-j)>len2)
                continue;

            //还要注意字符串数字的最高位在字符串的最低位所以得用len减去 
            tmp += (strNum1[len1-j]-'0') * (strNum2[len2-(i-j)]-'0');
        }
        //加上进位
        tmp += bit;
        //为了防止最后一位是0,但是却加上了
        if (tmp == 0 && i == len1+len2+1) 
            break;
        //求余得到结果的第i位
        strMultiply += tmp % 10 + '0';
        //计算新的进位
        bit = tmp / 10; 
    }

    //判断结果的最后一个字符如果是0的话说明可以删去
    //if (strMultiply[strMultiply.size()-1] == '0')
    // strMultiply[strMultiply.size()-1] = '\0';

    //反转
    reverse(strMultiply.begin(), strMultiply.end()); 

    return strMultiply;
}

int main()
{
    string str1;
    string str2;
    cin >> str1 >> str2;

    //相加和相乘
    cout << BigNumAdd(str1, str2) << endl;
    cout << BigNumMultiply(str1, str2) << endl; 

    int n;
    cin >> n;

    //阶乘 
    string rlt("1");
    string opNum;
    for (int i=1; i<=n; ++i)
    {
        //ss不可以定义在for循环外
        stringstream ss; 
        ss << i;
        ss >> opNum;

        rlt = BigNumMultiply(rlt, opNum); 
    }
    cout << rlt << endl;

    return 0;
}

输入:

123111111111
45622222222
5

输出:

168733333333
5616602469103375308642
120
    原文作者:大整数乘法问题
    原文地址: https://blog.csdn.net/u013457167/article/details/82316481
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞