一、简介
- 由于编程语言提供的基本数值数据类型表示的数值范围有限,不能满足较大规模的高精度数值计算,因此需要利用其他方法实现高精度数值的计算,于是产生了大数运算。
二、大数乘法
- 大数乘法大致有以下几种算法:模拟手工计算的普通大数乘法,分治算法和FFT算法。
-
模拟普通手算乘法:算法简单、空间复杂度小。时间复杂度为O(n^2)。
利用代数方法优化的乘法:使用递归求解,空间复杂度较大。算法复杂,需要定义大数加法,大数减法。时间复杂度降低到O(n^1.5)。
快速傅立叶变换FFT:基于FFT的大数乘法时间复杂度O(nlogn)。
- 下面例子是模拟普通手算乘法,其他两种可看参考文章
- 思路
乘积是逐位相乘,也就是ai*bj,结果加入到积C的第i+j位,最后处理进位即可
①字符中转换为int,并反转
②逐位相乘,结果存放在result_num[i+j]中;
③处理进位,消除多余的0;
④转换并反转,将计算结果转换为字符串并反转。
- 头文件和数据结构
#include <iostream> #include <string> #include <vector> #include <stdlib.h> using namespace std; struct bigcheng { vector<int> a; vector<int> b; string result_str; }; void chartonum(string a,string b,bigcheng &tempcheng);//字符串转换为数字并反转 void multiply(bigcheng &tempchengh,vector<int> &result_num);//逐位相乘,处理进位消除多余的0 void numtochar(bigcheng &tempcheng,vector<int> &result_num);//将计算结果转换为字符串并反转
- ①字符中转换为int,并反转
void chartonum(string a,string b,bigcheng &tempcheng) { int size_a=a.size(); int size_b=b.size(); for (int i=size_a-1;i>=0;i--) { tempcheng.a.push_back(a[i]-'0'); } for (int i=size_b-1;i>=0;i--) { tempcheng.b.push_back(b[i]-'0'); } }
- ②逐位相乘,结果存放在result_num[i+j]中;
③处理进位,消除多余的0;void multiply(bigcheng &tempcheng,vector<int> &result_num) { for (unsigned int i=0;i<tempcheng.a.size();i++) { for (unsigned int j=0;j<tempcheng.b.size();j++) { result_num[i+j]+=(tempcheng.a[i])*(tempcheng.b[j]); } } for (int i=result_num.size()-1;i>=0;i--) { if (result_num[i]!=0) { break; } else result_num.pop_back(); } int c=0; for (unsigned int i=0;i<result_num.size();i++)//处理进位 { result_num[i]+=c; c=result_num[i]/10; result_num[i]=result_num[i]%10; } if (c!=0) { result_num.push_back(c); } }
- ④转换并反转,将计算结果转换为字符串并反转。
void numtochar(bigcheng &tempcheng,vector<int> &result_num) { int size=result_num.size(); for (unsigned int i=0;i<result_num.size();i++) { tempcheng.result_str.push_back(char(result_num[size-1-i]+'0')); } }
- 主函数
int main() { bigcheng tempcheng; string a,b; cin>>a>>b; chartonum(a,b,tempcheng); vector<int> resultnum(a.size()+b.size(),0); multiply(tempcheng,resultnum); numtochar(tempcheng,resultnum); cout<<tempcheng.result_str<<endl; system("pause"); return 0; }
三、大数加法
- check合法性校验,校验字符串中是否有非数字。
bool check(char *p) { if (!p) { return 1; } int i=0; while(p[i]!='\0') { if (p[i]<'0'||p[i]>'9') { return 1; } else ++i; } return 0;//合法 }
char* bigadd(char *p1,char *p2)
{
if (check(p1)||check(p2))
{
throw exception("Invalid input!");
}
int len1=strlen(p1);
int len2=strlen(p2);
int len3=max(len1,len2)+1;
char *p3=new char[len3+1];
memset(p3,'0',len3);
p3[len3]='\0';
int index1=len1-1,index2=len2-1,index3=len3-1;
int carry=0;
while(index1>=0&&index2>=0)
{
int num=p1[index1--]-'0'+p2[index2--]-'0'+carry;
if (num>=10)
{
carry=1;
num-=10;
}
else
carry=0;
p3[index3--]=num+'0';
}
while(index1>=0)
{
int num=p1[index1--]-'0'+carry;
if (num>=10)
{
carry=1;
num-=10;
}
else
carry=0;
p3[index3--]=num+'0';
}
while(index2>=0)
{
int num=p1[index2--]-'0'+carry;
if (num>=10)
{
carry=1;
num-=10;
}
else
carry=0;
p3[index3--]=num+'0';
}
p3[index3]=carry?'1':'0';
return p3;
}
四、大数相减
char* bigminus(char *p1,char *p2,bool &flag)
{
if (check(p1)||check(p2))
{
throw exception("Invalid input!");
}
flag=0;//正数默认
if (strlen(p1)<strlen(p2))
{
flag=1;
char *tmp=p1;
p1=p2;
p2=tmp;
}
else if (strlen(p1)==strlen(p2))
{
if (strcmp(p1,p2)<0)
{
flag=1;
char *tmp=p1;
p1=p2;
p2=tmp;
}
}
int index1=strlen(p1)-1,index2=strlen(p2)-1,index3=strlen(p1);
char *p3=new char[strlen(p1)+2];
memset(p3,'0',index3+1);
p3[index3+1]='\0';
int carry=0;
while(index1>=0&&index2>=0)
{
int num=p1[index1--]-p2[index2--]-carry;
if (num<0)
{
carry=1;
num+=10;
}
else carry=0;
p3[index3--]=num+'0';
}
while(index1>=0)
{
int num=p1[index1--]-'0'-carry;
if (num<0)
{
carry=1;
num+=10;
}
else carry=0;
p3[index3--]=num+'0' ;
}
int i=0;
while(p3[i]=='0') ++i;
if (flag)
{
p3[i-1]='-';
}
return p3;
}
五、大数相除
char* bigchu(char *p1,char *p2)//大数除,有问题,但思想是对的,关键怎么处理前面多样的0
{
bool flag=0;
char *tmp1=new char[strlen(p2)-strlen(p2)+1];
char *tmp0=tmp1,*p3,*p4;
memset(tmp1,'0',strlen(p2)-strlen(p2));
tmp1[strlen(p2)-strlen(p2)]='\0';
char *tmp2=bigminus(p1,p2,flag);
p1=tmp2;
while(!flag)
{
p3=bigadd(tmp0,"1");
tmp1=tmp0;
tmp0=p3;
delete []tmp1;
tmp2=bigminus(p1,p2,flag);
p4=p1;
p1=tmp2;
delete []p4;
}
return tmp0;
}