分治法實現大整數乘法
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
//string型別轉換成int型別
int string_to_num(string k)//string字串變整數型例如str="1234",轉換為整數的1234.
{
int back;
stringstream instr(k);
instr>>back;
return back;
}
//整形數轉換為string型別
string num_to_string(int intValue)
{
string result;
stringstream stream;
stream << intValue;//將int輸入流
stream >> result;//從stream中抽取前面放入的int值
return result;
}
//在字串str前新增s個零
string stringBeforeZero(string str,int s)
{
for(int i=0;i<s;i++)
{
str.insert(0,"0");
}
return str;
}
//兩個大整數字符串相加,超出計算機表示範圍的數也能實現相加(本函式可以實現大整數加法運算)
string stringAddstring(string str1,string str2)
{
//假定str1和str2是相等的長度,不相等時在前面自動補零,使兩個字串長度相等
if (str1.size() > str2.size())
{
str2 = stringBeforeZero(str2,str1.size() - str2.size());
}else if (str1.size() < str2.size())
{
str1 = stringBeforeZero(str1,str2.size() - str1.size());
}
string result;
int flag=0;//前一進位是否有標誌,0代表無進位,1代表有進位
for(int i=str1.size()-1;i>=0;i--)
{
int c = (str1[i] - '0') + (str2[i] - '0') + flag;//利用ASCII碼對字元進行運算,這裡加上flag代表的是:當前一位有進位時加1,無進位時加0
flag = c/10;//c大於10時,flag置為1,否則為0
c %= 10;//c大於10時取模,否則為其本身
result.insert(0,num_to_string(c));//在result字串最前端插入新生成的單個字元
}
if (0 != flag) //最後一為(最高位)判斷,如果有進位則再添一位
{
result.insert(0,num_to_string(flag));
}
return result;
}
/*兩個大整數字符串相減,超出計算機表示範圍的數也能實現相減(在這裡比較特殊,第一個引數一定大於第二個引數,
因為:a1*b0+a0*b1=(a1+a0)*(b1+b0)-(a1*b1+a0*b0) > 0 ,所以(a1+a0)*(b1+b0) > (a1*b1+a0*b0)
這個函式的兩個引數,第一個代表的其實就是(a1+a0)*(b1+b0),第二個代表的其實就是(a1*b1+a0*b0)
所以本函式裡不用考慮最終得到結果為負數的情況,至於計算有關大整數負數相乘的問題可以通過其他途徑判斷
*/
string stringSubtractstring(string str1,string str2)
{
//對傳進來的兩個數進行修剪,如果前面幾位有0則先去掉,便於統一處理
while ('0' == str1[0]&&str1.size()>1)
{
str1=str1.substr(1,str1.size()-1);
}
while ('0' == str2[0]&&str2.size()>1)
{
str2=str2.substr(1,str2.size()-1);
}
//使兩個字串長度相等
if (str1.size() > str2.size())
{
str2 = stringBeforeZero(str2,str1.size() - str2.size());
}
string result;
for(int i=str1.size()-1;i>=0;i--)
{
int c = (str1[i] - '0') - (str2[i] - '0');//利用ASCII碼進行各位減法運算
if (c < 0) //當不夠減時向前一位借位,前一位也不夠位時再向前一位借位,依次如下
{
c +=10;
int prePos = i-1;
char preChar = str1[prePos];
while ('0' == preChar)
{
str1[prePos]='9';
prePos -= 1;
preChar = str1[prePos];
}
str1[prePos]-=1;
}
result.insert(0,num_to_string(c));//在result字串最前端插入新生成的單個字元
}
return result;
}
//在字串str後跟隨s個零
string stringFollowZero(string str,int s)
{
for(int i=0;i<s;i++)
{
str.insert(str.size(),"0");
}
return str;
}
//分治法大整數乘法實現函式
string IntMult(string x,string y)//遞迴函式
{
//對傳進來的第一個數進行修剪,如果前面幾位有0則先去掉,便於統一處理
while ('0' == x[0]&&x.size()>1)
{
x=x.substr(1,x.size()-1);
}
//對傳進來的第二個數進行修剪,如果前面幾位有0則先去掉,便於統一處理
while ('0' == y[0]&&y.size()>1)
{
y=y.substr(1,y.size()-1);
}
/*這裡的f變數代表在兩個資料字串長度不想等或者不是2的指數倍的情況下,所要統一的長度,這樣做是為了讓資料長度為2的n次方
的情況下便於利用分治法處理
*/
int f=4;
/*當兩字串中有任意一個字串長度大於2時都要通過與上面定義的f值進行比較,使其達到資料長度為2的n次方,實現方式是在前面
補0,這樣可以保證資料值大小不變
*/
if (x.size()>2 || y.size()>2)
{
if (x.size() >= y.size()) //第一個數長度大於等於第二個數長度的情況
{
while (x.size()>f) //判斷f值
{
f*=2;
}
if (x.size() != f)
{
x = stringBeforeZero(x,f-x.size());
y = stringBeforeZero(y,f-y.size());
}
}else//第二個數長度大於第一個數長度的情況
{
while (y.size()>f) //判斷f值
{
f*=2;
}
if (y.size() != f)
{
x = stringBeforeZero(x,f-x.size());
y = stringBeforeZero(y,f-y.size());
}
}
}
if (1 == x.size()) //資料長度為1時,在前面補一個0(這裡之所以會出現長度為1的資料是因為前面對資料修剪過)
{
x=stringBeforeZero(x,1);
}
if (1 == y.size()) //資料長度為1時,在前面補一個0(這裡之所以會出現長度為1的資料是因為前面對資料修剪過)
{
y=stringBeforeZero(y,1);
}
if (x.size() > y.size()) //最後一次對資料校正,確保兩個資料長度統一
{
y = stringBeforeZero(y,x.size()-y.size());
}
if (x.size() < y.size()) //最後一次對資料校正,確保兩個資料長度統一
{
x = stringBeforeZero(x,y.size()-x.size());
}
int s = x.size();
string a1,a0,b1,b0;
if( s > 1)
{
a1 = x.substr(0,s/2);
a0 = x.substr(s/2,s-1);
b1 = y.substr(0,s/2);
b0 = y.substr(s/2,s-1);
}
string result;
if( s == 2) //長度為2時代表著遞迴的結束條件
{
int na = string_to_num(a1);
int nb = string_to_num(a0);
int nc = string_to_num(b1);
int nd = string_to_num(b0);
result = num_to_string((na*10+nb) * (nc*10+nd));
}
else{ //長度不為2時利用分治法進行遞迴運算
/***************************************************
小提示:
c = a*b = c2*(10^n) + c1*(10^(n/2)) + c0;
a = a1a0 = a1*(10^(n/2)) + a0;
b = b1b0 = b1*(10^(n/2)) + b0;
c2 = a1*b1; c0 = a0*b0;
c1 = (a1 + a0)*(b1 + b0)-(c2 + c0);
****************************************************/
string c2 = IntMult(a1,b1);// (a1 * b1)
string c0 = IntMult(a0,b0);// (a0 * b0)
string c1_1 = stringAddstring(a1,a0);// (a1 + a0)
string c1_2 = stringAddstring(b1,b0);// (b1 + b0)
string c1_3 = IntMult(c1_1,c1_2);// (a1 + a0)*(b1 + b0)
string c1_4 = stringAddstring(c2,c0);// (c2 + c0)
string c1=stringSubtractstring(c1_3,c1_4);// (a1 + a0)*(b1 + b0)-(c2 + c0)
string s1=stringFollowZero(c1,s/2);// c1*(10^(n/2))
string s2=stringFollowZero(c2,s);// c2*(10^n)
result = stringAddstring(stringAddstring(s2,s1),c0);// c2*(10^n) + c1*(10^(n/2)) + c0
}
return result;
}
void main()
{
int f=1;
while (1 == f)
{
string A,B,C,D;
string num1,num2;
string r;
cout<<"大整數乘法運算(分治法實現)"<<endl;
cout<<"請輸入第一個大整數(任意長度):";
cin>>num1;
int i=0;
//判斷第一個輸入的資料是否合法,當字串中包含非數字字元時提示使用者重新輸入
for(i=0 ;i < num1.size();i++)
{
if (num1[i]<'0' || num1[i]>'9')
{
cout<<"您輸入的資料不合法,請輸入有效的整數!"<<endl;
cin>>num1;
i=-1;
}
}
cout<<"請輸入第二個大整數(任意長度):";
cin>>num2;
//判斷第二個輸入的資料是否合法,當字串中包含非數字字元時提示使用者重新輸入
for(i=0 ;i < num2.size();i++)
{
if (num2[i]<'0' || num2[i]>'9')
{
cout<<"您輸入的資料不合法,請輸入有效的整數!"<<endl;
cin>>num2;
i=-1;
}
}
r=IntMult(num1,num2);
//對求得的結果進行修剪,去掉最前面的幾個0
while ('0' == r[0]&&r.size()>1)
{
r=r.substr(1,r.size()-1);
}
cout<<"兩數相乘結果為:"<<endl;
cout<<num1<<" "<<"*"<<" "<<num2<<" "<<"="<<" "<<r<<endl<<endl;
}
}
//本程式轉載請說明出處,謝謝,非常感謝大家提出寶貴的建議!