c++大整数乘法
2021/5
利用二分法和递归计算任意长度整数相乘
以下复杂度分析有问题,在于 划分为 A12(n2),这样才相当于移位;
程序中采用string直接+'0'的方式来*10
第一次的代码有漏洞,已更正
我们可以把规模n变成n/2和n/2(把以1位为单位规模为n的问题 变成 以n/2为单位的规模为2的问题),把规模m变成m/2和m/2(把以1位为单位规模为m的问题 变成 以m/2为单位的规模为2的问题),如此,原来的大整数相乘就变成了两个2位数相乘,只不过低位向高位的进制不再是10,而是和。更一般地,我们把整数A由规模n分为n1和n2,把整数B由规模m分为m1和m2,如下图:
则A分为n1位的A1和n2位,B分为m1位的B1和m2位的B2,如下式所示:
以此类推,我们可以把A1、A2、B1、B2继续划分,直至最小单位。(这里在编程时需要用递归实现)
于是
注意用2^n做乘法相当于移位运算,需要O(n)时间。此公式中有4次乘法运算,3次加法运算,则
故T(n)=O(n^2)
而
A1B1 A2B2已经计算过,故乘法运算次数减少为3次
产生递推式
```
// 四次乘法,3次加法
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
string multi(string A, string B); //计算大整数相乘
string Plus(string q, string w, string e, string r); //计算大整数相加
stringstream ss;
int main() {
string A, B;
while (cin >> A >> B) {
cout << multi(A, B) << endl;
}
return 0;
}
string multi(string A, string B) {
int len_A = A.length();
int len_B = B.length();
if (len_A == 1) {
if (len_B == 1) { //最基本的情况:A和B都是一位数,把A、B从string转为int(我这里用的stringstream),然后相乘后转回为string型return回去。
ss << A;
int a;
ss >> a;
ss.clear();
ss << B;
int b;
ss >> b;
ss.clear();
ss << b*a;
string str_out;
ss >> str_out;
ss.clear();
return str_out;
}
else {//A是个位数,B不是的情况下,按照分治的思想把B分开分别与A相乘。
string B1, B2;
B1 = B.substr(0, len_B / 2);
B2 = B.substr(len_B / 2);
string AB1 = multi(A, B1);
string AB2 = multi(A, B2);
cout<<AB1<<endl<<AB2<<endl;
if (AB2.length() > B2.length()) { //此时AB2最多比B2多出一位
string str = AB2.substr(0, 1);
/*ss << AB1; 漏洞,此时AB1可能已经超出int范围了
int ab1;
ss >> ab1;*/
string tp0(AB1.length()-1,'0');
str=tp0+str;
string u0(AB1.length(),'0');
AB1=Plus(AB1,str,u0,u0);
return AB1 + AB2.substr(1);
}
else
return AB1 + AB2;
}
}
else {
if (len_B == 1) {//B是个位数,A不是的情况与上述A是个位数B不是的情况相同。
string A1, A2;
A1 = A.substr(0, len_A / 2);
A2 = A.substr(len_A / 2);
string A1B = multi(A1, B);
string A2B = multi(A2, B);
if (A2B.length() > A2.length()) {
string str = A2B.substr(0, 1);
string tp0(A1B.length()-1,'0');
str=tp0+str;
string u0(A1B.length(),'0');
A1B=Plus(A1B,str,u0,u0);
return A1B + A2B.substr(1);
}
else {
return A1B + A2B;
}
}
else {//A和B都不是个位数,就按照上述方法分治就可以了,只是为了最后相加的时候方便,把返回的四个部分都用0凑成了位数相同的。
string A1, A2, B1, B2;
A1 = A.substr(0, len_A / 2);
A2 = A.substr(len_A / 2);
B1 = B.substr(0, len_B / 2);
B2 = B.substr(len_B / 2);
string part1_ = multi(A1, B1);
string part1_0(A2.length()+B2.length(), '0'); //长度为A2.length()+B2.length()的0串
part1_ = part1_ + part1_0; //A1B1*10(n2,m2)
string part2_ = multi(A2, B2);
string part2_00(part1_.length() - part2_.length(), '0');
part2_ = part2_00 + part2_; //A2B2,高位补0
string part3_ = multi(A1, B2);
string part3_0(A2.length(), '0');
part3_ = part3_ + part3_0; //A1B2*10(n2)
string part3_00(part1_.length() - part3_.length(), '0');
part3_ = part3_00 + part3_;
string part4_ = multi(A2, B1);
string part4_0(B2.length(), '0');
part4_ = part4_ + part4_0;
string part4_00(part1_.length() - part4_.length(), '0');
part4_ = part4_00 + part4_;
return Plus(part1_, part2_, part3_, part4_); //未改进的第一种算法
}
}
}
string Plus(string q, string w, string e, string r) { //大整数相加,qwer位数相同
int len_q = q.length();
string y, out;
int a, b, c, d;
for (int i = 1; i <= len_q; i++) { //逐位相加
ss << q.substr(len_q - i, 1);
ss >> a;
ss.clear();
ss << w.substr(len_q - i, 1);
ss >> b;
ss.clear();
ss << e.substr(len_q - i, 1);
ss >> c;
ss.clear();
ss << r.substr(len_q - i, 1);
ss >> d;
ss.clear();
ss << a + b + c + d;
ss >> y;
ss.clear();
if (i == 1)
out = y;
else if (out.length() > i - 1) { //进一位
ss << out.substr(0, 1);
ss >> a;
ss.clear();
ss << y;
ss >> b;
ss.clear();
ss << a + b;
ss >> y;
ss.clear();
out = y + out.substr(1);
}
else {
out = y + out;
}
}
return out;
}
```
```
// 三次乘法。由于还没有实现大整数减法(或支持负数的加法),暂时还是伪代码 #include <iostream> #include <string> #include <sstream> using namespace std; string multi(string A, string B); //计算大整数相乘 string Plus(string q, string w, string e, string r); //计算大整数相加 stringstream ss; int main() { string A, B; while (cin >> A >> B) { cout << multi(A, B) << endl; } return 0; } string multi(string A, string B) { int len_A = A.length(); int len_B = B.length(); if (len_A == 1) { if (len_B == 1) { //最基本的情况:A和B都是一位数,把A、B从string转为int(我这里用的stringstream),然后相乘后转回为string型return回去。 ss << A; int a; ss >> a; ss.clear(); ss << B; int b; ss >> b; ss.clear(); ss << b*a; string str_out; ss >> str_out; ss.clear(); return str_out; } else {//A是个位数,B不是的情况下,按照分治的思想把B分开分别与A相乘。 string B1, B2; B1 = B.substr(0, len_B / 2); B2 = B.substr(len_B / 2); string AB1 = multi(A, B1); string AB2 = multi(A, B2); cout<<AB1<<endl<<AB2<<endl; if (AB2.length() > B2.length()) { //此时AB2最多比B2多出一位 string str = AB2.substr(0, 1); /*ss << AB1; 漏洞,此时AB1可能已经超出int范围了 int ab1; ss >> ab1;*/ string tp0(AB1.length()-1,'0'); str=tp0+str; string u0(AB1.length(),'0'); AB1=Plus(AB1,str,u0,u0); return AB1 + AB2.substr(1); } else return AB1 + AB2; } } else { if (len_B == 1) {//B是个位数,A不是的情况与上述A是个位数B不是的情况相同。 string A1, A2; A1 = A.substr(0, len_A / 2); A2 = A.substr(len_A / 2); string A1B = multi(A1, B); string A2B = multi(A2, B); if (A2B.length() > A2.length()) { string str = A2B.substr(0, 1); string tp0(A1B.length()-1,'0'); str=tp0+str; string u0(A1B.length(),'0'); A1B=Plus(A1B,str,u0,u0); return A1B + A2B.substr(1); } else { return A1B + A2B; } } else {//A和B都不是个位数,就按照上述方法分治就可以了,只是为了最后相加的时候方便,把返回的四个部分都用0凑成了位数相同的。 string A1, A2, B1, B2; A1 = A.substr(0, len_A / 2); A2 = A.substr(len_A / 2); B1 = B.substr(0, len_B / 2); B2 = B.substr(len_B / 2); string part1_ = multi(A1, B1); part1_ = multi(2, part1_); string part1_0(A2.length()+B2.length(), '0'); //长度为A2.length()+B2.length()的0串 part1_ = part1_ + part1_0; //2*A1B1*10(n2,m2) string part2_ = multi(A2, B2); part2_ =multi(2,part2_); string part2_00(part1_.length() - part2_.length(), '0'); part2_ = part2_00 + part2_; //2*A2B2,高位补0 string part3_ = A1; string part3_0(A2.length(), '0'); //(A1*10(n2)-A2) part3_ = part3_ + part3_0; //A1*10(n2) 伪代码 part3_= part_3-A2 //大整数减法(或支持负数的大整数加法),未实现 string part4_ = B1; //(B2-B1*10(m2)) string part4_0=(B2.length(), '0'); part4_ = part4_ + part4_0; part4_= B2-part4_; part5_= multi(part4_,part3_) string part5_00(part1_.length() - part5_.length(), '0'); part5_ = part5_00 + part5_; string u0(part1_.length(), '0'); return Plus(part1_, part2_, part5_, u0); } } } string Plus(string q, string w, string e, string r) { //大整数相加,qwer位数相同 int len_q = q.length(); string y, out; int a, b, c, d; for (int i = 1; i <= len_q; i++) { //逐位相加 ss << q.substr(len_q - i, 1); ss >> a; ss.clear(); ss << w.substr(len_q - i, 1); ss >> b; ss.clear(); ss << e.substr(len_q - i, 1); ss >> c; ss.clear(); ss << r.substr(len_q - i, 1); ss >> d; ss.clear(); ss << a + b + c + d; ss >> y; ss.clear(); if (i == 1) out = y; else if (out.length() > i - 1) { //进一位 ss << out.substr(0, 1); ss >> a; ss.clear(); ss << y; ss >> b; ss.clear(); ss << a + b; ss >> y; ss.clear(); out = y + out.substr(1); } else { out = y + out; } } return out; }
```
部分参考
https://blog.csdn.net/qq_36165148/article/details/81132525
Before
这里不是必须用c++的话不推荐用c++大整数,py和java的支持要好得多。
大整数类 (非负)
#include <iostream>
#include <vector>
#include <string>
using namespace std;
struct BigInteger{
static const int BASE=100000000;
static const int WIDTH=8;
vector<int> s;
BigInteger(long long num=0){*this = 0}//构造函数
BigInteger operator =(long long num){
s.clear();
do{
s.push_back(num%BASE);
num/=BASE;
}while(num>0);
return *this;
}
BigInteger operator = (const string& str){
s.clear();
int x,len=(str.length()-1)/WIDTH+1;
for(int i=0;i<len;i++){
int end=s.length()-i*WIDTH;
int start=max(0,end-WIDTH);
sscanf(str.substr(start,end).c_str(),"%d",&x);
s.push_back(x);
}
return *this;
}
BigInteger operator + (const BigInteger &b) const {
BigInteger c;
c.s.clear();
int i,g;
int x;
for(i=0,g=0;;i++){
if(g==0&&i>=s.size()&&i>=b.s.size()){//无进位,两个BigInteger实例均已遍历完成
break;
x=g;
if(i<s.size())
x+=s[i];
if(i<b.s.size())
x+=b.s[i];
c.s.push_back(x%BASE);
g=x/BASE;
}
return c;
}
BigInteger operater+=(const BigInteger &b){
*this=*this+b;return *this;
}
BigInteger operator - (const BigInteger& b) const
{
BigInteger c;
c.s.clear();
int MAX=std::max(s.size(),b.s.size());
for(int i=0,g=0;;i++)
{
if(g==0&&i>=MAX)
break;
int x=g;
if(i<s.size())
x+=s[i];
if(i<b.s.size())
x-=b.s[i];
if(i==MAX-1)
c.s.push_back(x%BASE);
else
c.s.push_back(abs(x%BASE));
g=x/BASE;
}
return c;
}
BigInteger operator -= (const BigInteger& b)
{
*this=*this-b;
return *this;
}
BigInteger operator * (const BigInteger& b)
{
std::stringstream ss;
for(int i=s.size()-1;i>=0;i--)
ss<<s[i];
std::string operand1=ss.str();
ss.str("");
for(int i=b.s.size()-1;i>=0;i--)
ss<<b.s[i];
std::string operand2=ss.str();
std::vector<int> c,d,temp;
for(int i=operand1.length()-1;i>=0;i--)
c.push_back(operand1[i]-'0');
for(int i=operand2.length()-1;i>=0;i--)
d.push_back(operand2[i]-'0');
int MAX=std::max(c.size(),d.size());
for(int i=0;i<MAX*2+1;i++)
temp.push_back(0);
for(int i=0;i<c.size();i++)
for(int j=0;j<d.size();j++)
temp[i+j]+=c[i]*d[j];
for(int i=0;i<2*MAX+1;i++)
if(temp[i]>9)
{
temp[i+1]+=temp[i]/10;
temp[i]%=10;
}
int m=2*MAX;
while(temp[m]==0)
m--;
BigInteger another;
another.s.clear();
int len=(m-1)/WIDTH+1;
for(int i=0;i<len;i++)
another.s.push_back(0);
for(int i=0;i<len;i++)
{
int x=1;
int k=0;
int end=std::min(m+1,(i+1)*WIDTH);
int start=i*WIDTH;
for(int j=start;j<end;j++)
{
k+=x*temp[j];
x*=10;
}
another.s[i]=k;
}
return another;
}
BigInteger operator *= (const BigInteger& b)
{
*this=*this*b;
return *this;
}
//自己写的除法,可以实现像int型一样的效果
BigInteger operator / (const BigInteger& b)
{
std::string operand1,operand2,result;
std::stringstream ss;
for(int i=s.size()-1;i>=0;i--)
ss<<s[i];
operand1=ss.str();
ss.str("");
for(int i=b.s.size()-1;i>=0;i--)
ss<<b.s[i];
operand2=ss.str();
int len1,len2;
len1=operand1.length();
len2=operand2.length();
if(len1<len2) //若操作数1小于操作数2,返回0
return 0;
if(*this==b) //若两数相等,返回1,这里用到下面的“==”重载运算符
return 1;
std::vector<int> c,d;
for(int i=0;i<len1;i++)
{
c.push_back(operand1[i]-'0');
if(i<len2)
d.push_back(operand2[i]-'0');
else
d.push_back(0);
}
int time=len1-len2;
int len=len1;
int k,l=0;
for(int i=0;i<=time;i++)
{
int ok=1;
k=0;
do{
if(c[l]==0)
{
l++;
ok=0;
len1--;
}
if(len==len1)
{
int j=0;
while(j<len2)
{
if(c[i+j]>d[j]) //第一次大就表示operand1 > operand2
{
ok=1;
break;
}
else if(c[i+j]<d[j]) //第一次小就表示operand1 < operand2
{
ok=0;
break;
}
j++;
}
}
if(ok)
{
for(int j=0;j<len;j++)
{
c[j+i]-=d[j];
if(c[j+i]<0)
{
c[j+i-1]--;
c[j+i]+=10;
}
}
k++;
}
}while(ok);
len--;
result+=k+'0';
}
BigInteger temp;
temp=result;
return temp;
}
BigInteger operator /= (const BigInteger& b)
{
*this=*this/b;
return *this;
}
//以下的重载方法全都在上面的四则运算上编写,不再介绍
BigInteger operator % (const BigInteger& b)
{
BigInteger c;
c=*this-(*this/b)*b;
return c;
}
BigInteger operator %= (const BigInteger& b)
{
*this=*this%b;
return *this;
}
bool operator < (const BigInteger& b) const
{
if(s.size()!=b.s.size())
return s.size()<b.s.size();
for(int i=s.size()-1;i>=0;i--)
if(s[i]!=b.s[i])
return s[i]<b.s[i];
return false;//相等
}
bool operator > (const BigInteger& b) const
{
return b<*this;
}
bool operator <= (const BigInteger& b) const
{
return !(b<*this);
}
bool operator >= (const BigInteger& b) const
{
return !(*this<b);
}
bool operator != (const BigInteger& b) const
{
return *this<b||*this>b;
}
bool operator == (const BigInteger& b) const
{
return !(*this<b)&&!(*this>b);
}
friend std::ostream& operator << (std::ostream& out,const BigInteger& x)
{
out<<x.s.back();
for(int i=x.s.size()-2;i>=0;i--)
{
char buf[20];
sprintf(buf,"%08d",x.s[i]);
for(int j=0;j<strlen(buf);j++)
out<<buf[j];
}
return out;
}
friend std::istream& operator >> (std::istream& in,BigInteger& x)
{
std::string s;
if(!(in>>s))
return in;
x=s;
return in;
}
};
istream& operator >> (istream &in, BigInteger &x){
string s;
if(!(in>>x)) return in;
x=s;
return in;
}
ostream& operator << (ostream &out,const BigInteger &x){
out << x.s.back();//最高位不足8位的预防处理
int i;
for(i=x.s.size()-2;i>=0;i--){
char buf[20];
sprintf(buf,"%08d",x.s[i]);//不足8位补0
for(int j=0;j<strlen(buf);j++)
out<<buf[j];
}
return out;
}
说明: static const int BASE=100000000;这个常数不属于 BigInteger类型的结构体变量,而属于 BigInteger这个类型,称为静态成员变量。在 BigInteger的成员函数内可以直接使用,但是在其他地方,用 BigInteger::BASE