两个超级大整数的相加,相乘

Posted 后营马族子弟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了两个超级大整数的相加,相乘相关的知识,希望对你有一定的参考价值。

我们很容易理解两个超级大的整数的相加或者相乘不能用int,long, long long 来承载,因为还是很可能溢出。

我们c,c++语言起步的,很容易想到用char数组或者string来无限承载超大数。我开始也这么想的。后面突然想到vector<int>也可以承载。其实没有差别。

很多同学写不出两个超大数的乘法,这里提供一个解法:

(1)核心是数据规范化,比如有个数串: [低位] 30,45,21,100[高位] 我们需要转成: 0,8,5,2,0,1 即把进位体现在他的高位中(对于30,需要留下0然后把3进位到高位去.所以45会编出45+3=48. 对于48,需要留下8,把4进位到高位去,所以21+4=25. 。。。。。。. 对于最后一个100,需要加2: 100+2=102,然后留下2,把10进位到高位:0+10=10(高位初始化为0)。 留下0,把1进位到高位: 0+1=1 . 1<9所以无需再进位计算了)。

(2) 我们还需要写一个两个大数相加,因为我们很容易知道45*32可以转出45*2 + 45*30 。 所以可以把45*2作为一个大数,45*30作为一个大数,求这两个大数的和。所以需要写两个大数相加的函数。

(3)最后我们写一个两个大数的乘法,然后把各层乘法当作一个大数进行加操作。比如45*32,我们吧45*2的结果作为一个大数, 45*30的结果作为一个大数。然后进行上面的大数相加计算。

具体例子如下:

#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<math.h>


using namespace std;

void showV(const vector<int>& obj) //打印
{
    for(int i = 0; i < obj.size(); ++i)
    {
        cout << obj[i] << "/";
    }
}
///////////////////////单个一串数字变换成正常的数值的函数/////////////////////////////////////
//103,35,23,15--变换成整数值--->106745 (大数在左,小数在右)
const vector<int> getNum(const vector<int>& obj)
{
    vector<int> newNum(obj);
    reverse(newNum.begin(), newNum.end()); //把数值整体翻转,这样就可以下标0对应最低位,算进制的时候从下标0开始向下标size-1开始算起

    for(int i = 0; i < newNum.size(); ++i)
    {
        if (newNum[i] > 9) //如果当前下标对应的数据>= 10,则 value/10表示进制,value%10表示剔除进制后的真正数据
        {
            newNum[i+1] += newNum[i]/10; //i+1的位置自加来自低位的进制
            newNum[i] = newNum[i]%10;
        }

        //当把倒数第二个算完后,倒数第二个的进制已经在最后一个上体现了。如果最后一个的数值>=10,那么则需要在最后一个后面再添加一个位置进行进制的进位
        if (i == newNum.size() - 2)
        {
            if( newNum[newNum.size()-1] >= 10 )
            {
                newNum.push_back(0);
            }
        }
    }

    reverse(newNum.begin(), newNum.end()); //上面为了计算方便所以数据整体翻转了,这里再翻转回来。
    return newNum;

}

void test_getNum()
{
    vector<int> tmp;
    tmp.push_back(103);
    tmp.push_back(35);
    tmp.push_back(23);
    tmp.push_back(15);
    vector<int> digital =  getNum(tmp);
    showV(digital);
    cout<<endl;
}
/////////////////////////////////两个大数相加的函数/////////////////////////////////////////////
const vector<int> addVec(vector<int> addLeft, vector<int> addRight)
{
    addLeft = getNum(addLeft);
    addRight = getNum(addRight);

    vector<int> sum;

    reverse(addLeft.begin(), addLeft.end());
    reverse(addRight.begin(), addRight.end());
    if (addLeft.size() > addRight.size()) //翻转之后就成了先低位对齐,然后从低位加到高位
    {
        sum = addLeft;
        for(int i = 0; i < addRight.size(); ++i)
        {
            sum[i] += addRight[i];
        }
    }
    else
    {
        sum = addRight;
        for(int i = 0; i < addLeft.size(); ++i)
        {
            sum[i] += addLeft[i];
        }
    }

    reverse(sum.begin(), sum.end());
    sum = getNum(sum);
    return sum;
}

void test_addVec()
{
    vector<int> first;
    first.push_back(7);
    first.push_back(8);
    first.push_back(2);
    first.push_back(3);
    first.push_back(4);

    vector<int> second;
    second.push_back(9);
    second.push_back(9);
    second.push_back(9);
    second.push_back(9);
    second.push_back(9);
    second.push_back(0);


    showV(first);
    cout<<endl;
    showV(second);
    cout<<endl;

    vector<int> sum = addVec(first, second);
    showV(sum);
    cout<<endl;
}
////////////////////////////两个大数相乘的函数////////////////////////////////////////
#if 0
/* bug 版本 : 因为两个数都可以无限大,所以curNum确定不会越限? 所以有bug*/ const vector<int> mulVec(vector<int> mulLeft, vector<int> mulRight) { vector<int> result(1,0); reverse(mulRight.begin(), mulRight.end()); for(int i = 0; i < mulRight.size(); ++i) { vector<int> thisLoopValue(mulLeft); int curNum = mulRight[i] * (int)pow(10,i); for(int j = 0; j < thisLoopValue.size(); ++j) { thisLoopValue[j] *= curNum; } thisLoopValue = getNum(thisLoopValue); result = addVec(result, thisLoopValue); } result = getNum(result); return result; } #endif

const vector<int> mulVec(vector<int> mulLeft, vector<int> mulRight)
{
    vector<int> result(1,0);


    reverse(mulRight.begin(), mulRight.end());
    for(int i = 0; i < mulRight.size(); ++i)
    {
        vector<int> thisLoopValue(mulLeft);


        //long long curNum = mulRight[i] * (long long)pow(10,i);
       long long curNum = mulRight[i];


       for(int j = 0; j < thisLoopValue.size(); ++j)
       {
      thisLoopValue[j] *= curNum;
    }
    for(int k = 0; k < i; k++) //往最末尾补0. 比如计算25*21时候 算25*20 可以算25*2,在得出的结果最小数那里塞进一个0进去,来等价25*20
    {
      thisLoopValue.push_back(0);
    }


    thisLoopValue = getNum(thisLoopValue);
    result = addVec(result, thisLoopValue);
    result = getNum(result);
}

return result;
}


void test_mulVec() { vector<int> first; first.push_back(8); first.push_back(8); first.push_back(9); first.push_back(0); first.push_back(2); first.push_back(9); first.push_back(8); first.push_back(8); first.push_back(1); vector<int> second; second.push_back(8); second.push_back(9); second.push_back(8); showV(first); cout<<endl; showV(second); cout<<endl; vector<int> mulResult = mulVec(first, second); showV(mulResult); cout<<endl; } ///////////////////////////////////////////// int main() { //test_getNum(); //test_addVec(); test_mulVec(); };


[mayc@ /data_disk2/Share/ftproot/myc]$./testme
8/8/9/0/2/9/8/8/1/
8/9/8/
7/9/8/3/4/8/8/3/3/1/3/8/

即: 889029881 * 898 = 798348833138
8/8/9/0/2/9/8/8/1/ * 8/8/9/0/2/9/8/8/1/ = 7/9/0/3/7/4/1/2/9/3/1/0/8/7/4/1/6/1/

 

以上是关于两个超级大整数的相加,相乘的主要内容,如果未能解决你的问题,请参考以下文章

java 很长的大数 如何用String 相加,相乘?

求两个大整数相乘的积,数字长度在127个字符之内。

[LeetCode]415. 字符串相加43. 字符串相乘

两个超级大数相加

将两个数字相乘然后相加

大整数相乘