两个超级大整数的相加,相乘
我们很容易理解两个超级大的整数的相加或者相乘不能用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/