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


    我们很容易理解两个超级大的整数的相加或者相乘不能用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表示剔除进制后的真正数据
            {
    if( (i+1) >= newNum.size() ) //如果newNum[i]>9 说明需要进位。 而i+1这个空间又不存在,那么先添加一个空间
    {
    newNum.push_back(0);
    } newNum[i
    +1] += newNum[i]/10; //i+1的位置自加来自低位的进制 newNum[i] = newNum[i]%10; } /* 用这种方式扩展有bug, 14的结果是4. 因为扩展是在上面的if{} 之后做的。 在if中不存在newNum[i+1]. 所以空间扩展挪到上面if中去做 //当把倒数第二个算完后,倒数第二个的进制已经在最后一个上体现了。如果最后一个的数值>=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/
  • 相关阅读:
    LightOJ1326 Race(DP)
    LightOJ1125 Divisible Group Sums(DP)
    HDU 5738 Eureka(极角排序)
    BZOJ 3223 Tyvj 1729 文艺平衡树(Splay)
    Codeforces 707D Persistent Bookcase(时间树)
    HDU 5809 Ants(KD树+并查集)
    HDU 5875 Function(ST表+二分)
    BZOJ 2002 [Hnoi2010]Bounce 弹飞绵羊(动态树)
    HDU 5737 Differencia(归并树)
    HDU 1512 Monkey King(左偏树+并查集)
  • 原文地址:https://www.cnblogs.com/silentNight/p/13910510.html
Copyright © 2020-2023  润新知