高精度(不使用STL的OJ)
用字符串或字符数组输入,
用数组存储与运算,
用数组输出结果
高精度加法
#include<iostream>
#include<cstring>
using namespace std;
char s1[505],s2[505];
int a[505],b[505],c[505];
int main(){
int m,n,v,t;
std::ios::sync_with_stdio(false);//取消cin,cout与stdio的同步
//如果使用文件输入输出的话,一定记住要把这条语句放在freopen()后面
//输入
cin>>s1>>s2;
m=strlen(s1);
n=strlen(s2);
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
//存储
for(int i=0;i<m;i++){
a[m-1-i]=s1[i]-'0';
}
for(int i=0;i<n;i++){
b[n-1-i]=s2[i]-'0';
}
m=max(m,n);
m++;
memset(c,0,sizeof(c));
//加法,进位运算
for(int i=0;i<m;i++){
v=a[i]+b[i];
if((c[i]+v)<10)
c[i]+=v;
else{
c[i+1]+=(c[i]+v)/10;
c[i]=(c[i]+v)%10;
}
}
//下面是一种更简单的做法,结果直接储存在a中
/*for(int i=0;i<m;i++){
a[i]+=b[i];
a[i+1]+=a[i]/10;
a[i]%=10;
}*/
if(c[m-1]==0) m--;
//输出
for(int i=m-1;i>=0;i--) cout<<c[i];
return 0;
}
高精度减法
和高精度加法的基本思路相同,不过在减法中,需要确定输入数字的相对大小来判断是否输出负号,还需要注意是否要"借位"。
#include<iostream>
#include<cstring>
using namespace std;
//比较两个数相对大小
bool compare(char s1[],char s2[]){
int u=strlen(s1),v=strlen(s2);
if(u!=v)
return u>v;
for(int i=0;i<u;i++)
if(s1[i]!=s2[i]) return s1[i]>s2[i];
return true;
}
int main(){
std::ios::sync_with_stdio(false);
int flag=1,i,j;
char s1[100005],s2[100005],s3[100005]; //这里为节省空间考虑,直接用char数组运算
cin>>s1>>s2;
if(compare(s1,s2));
else{//被减数较小时
flag=-1;
strcpy(s3,s1);
strcpy(s1,s2);
strcpy(s2,s3);
}
int u=strlen(s1),v=strlen(s2);
//从最后一位向前减
for(i=u-1,j=v-1;j>=0;i--,j--){
if(s1[i]<s2[j]){
s1[i-1]-=1;//借位
s3[i]=s1[i]-s2[j]+10+'0';//+"0"确保返回的是字符串
}
else s3[i]=s1[i]-s2[j]+'0';
}
for(;i>=0;i--) {
if(s1[i]<'0'){
s1[i-1]-=1;
s3[i]=s1[i]+10;
}
else s3[i]=s1[i];
} //s1数位大,所以还有s1减'0'
for(i=0;i<u-1&&s3[i]=='0';i++); //只到u-1的原因时
if(flag==-1) cout<<'-';
cout<<s3+i;
return 0;
}
高精度乘法
#include<iostream>
#include<cstring>
using namespace std;
char a[2005],b[2005];
int c[2005],d[2005],e[4005];
int u,v,w;
int main(){
int i,j;
cin>>a>>b;
u=strlen(a);
v=strlen(b);
memset(c,0,4005);
for(int i=0;i<u;i++)
c[u-1-i]=a[i]-'0';
for(int i=0;i<v;i++)
d[v-1-i]=b[i]-'0';
for(i=0;i<u;i++){
for(j=0;j<v;j++){
w=c[i]*d[j];
if(e[i+j]+w<10) e[i+j]+=w;
else{
e[i+j+1]+=(e[i+j]+w)/10;
e[i+j]=(e[i+j]+w)%10;
}
}
}
for(i=u+v-1;i>0&&e[i]==0;i--); //此处是为了不漏掉输出结果为0而将条件写为i>0
for(;i>=0;i--) cout<<e[i];
return 0;
}
高精度除法
高精度除法分两种,都是仿照竖式除法实现,一种是高精度除以低精度,较为容易实现,主要是利用一个数,在线处理:
#include<iostream>
#include<cstring>
#include<string>
using namespace std;
char s1[5005];
int a[5005],b,c[5005],x=0;
int main(){
cin>>s1>>b;
a[0]=strlen(s1);
for(int i=1;i<=a[0];i++) a[i]=s1[i-1]-48;
memset(c,0,sizeof(c));
for(int i=1;i<=a[0];i++){
c[i]=(x*10+a[i])/b;
x=(x*10+a[i])%b;
} //核心部分
x=1;
while(c[x]==0&&x<a[0]) x++;
for(;x<=a[0];x++) cout<<c[x];
return 0;
}
另一种,是运用逐次相减的方法确定出商和余数,代码如下:
#include<iostream>
#include<cstring>
using namespace std;
int a[5005],b[5005],c[5005],d[5005];
bool compare(int a[],int b[]){
if(a[0]!=b[0]) return a[0]>b[0];
for(int i=a[0];i>0;i--){
if(a[i]!=b[i]) return a[i]>b[i];
}
return true;
}
int main(){
std::ios::sync_with_stdio(false);
string s1,s2;
cin>>s1>>s2;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
a[0]=s1.length();
b[0]=s2.length();
for(int i=1;i<=a[0];i++) a[i]=s1[a[0]-i]-'0';
for(int i=1;i<=b[0];i++) b[i]=s2[b[0]-i]-'0';
c[0]=a[0]-b[0]+1;
for(int i=c[0];i>0;i--){ //c[0]代表最初a,b的数位差
memset(d,0,sizeof(d));
for(int j=1;j<=b[0];j++)
d[j+i-1]=b[j];
d[0]=b[0]+i-1; //先让b中存下的数与a在一个数量级
while(compare(a,d)){ //比较,如果a比较大,用a直接减去d,如果a比较小,下一次大循环中,d的位数会减一
c[i]++;
for(int i=1;i<=a[0];i++){
a[i]-=d[i];
if(a[i]<0){
a[i+1]--;
a[i]+=10;
}
}
while(a[0]>0&&a[a[0]]==0) a[0]--;
}
}
while(c[0]>1&&c[c[0]]==0) c[0]--;
cout<<"商:";
for(int i=c[0];i>0;i--) cout<<c[i];
cout<<endl<<"余数:";
for(int i=a[0];i>0;i--) cout<<a[i]; //a中最后剩下的就是余数
return 0;
}
高精度(可使用STL的OJ)
高精度加法
#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
vector<int> add(vector<int> &A,vector<int> &B)
{
vector<int> C;
int t=0;
for(unsigned int i=0; i<A.size() || i<B.size();i++)
{
if(i<A.size()) t+=A[i];
if(i<B.size()) t+=B[i];
C.push_back(t%10);
t/=10;
}
if(t) C.push_back(1);
return C;
}
int main() {
string a,b;
vector<int> A,B;
cin>>a>>b;
for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');
for(int i=b.size()-1;i>=0;i--) B.push_back(b[i]-'0');
vector<int> C=add(A,B);
for(int i=C.size()-1;i>=0;i--) cout<<C[i];
}
高精度加法+乘法(面向对象+压位)
z[i]实际上只存储了一个0到9的数,这样就造成了空间浪费。我们不妨把十进制换成高进制,如一亿进制,这样就可以较充分地利用空间,另外还可以大大提高程序的运行速率。具体做法就是将程序中的 /10,%10 换成 /k,%k(k是进制)。
值得注意的是,若将十进制换成高进制,c.z[i+j]+=a.z[i]b.z[j] 这一步操作就有可能会爆空间。我们可以设一个long long型的v来记录c.z[i]+1lla.z[i]*b.z[i],通过v向前进位,有效避免爆空间的情况 。
另外,我们一定不能忽略补零操作。举个例子,当k=100000000时,c.z[i]中存储的是23,直接输出23是错误的,若23不在第一位,就应输出0000023 。
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<string>
#include<algorithm>
using namespace std;
const int k=100000000;
struct gaojing{
int z[100000];
int l;
gaojing(){
memset(z,0,sizeof(z));
l=1;
}
friend istream& operator>>(istream &cin,gaojing &v){
static char s[100000];
cin>>s;
int l=strlen(s);
reverse(s,s+l);//stl中的翻转函数
for(int a=l-1;a>=0;a--)
v.z[a/8]=v.z[a/8]*10+s[a]-'0';
v.l=l/8;
if (l%8!=0) v.l++;
return cin;
}
friend ostream& operator<<(ostream &cout,const gaojing &v){
cout<<v.z[v.l-1];
for(int i=v.l-2;i>=0;i--){//补零操作
if(v.z[i]<10000000)cout<<'0';
if(v.z[i]<1000000)cout<<'0';
if(v.z[i]<100000)cout<<'0';
if(v.z[i]<10000)cout<<'0';
if(v.z[i]<1000)cout<<'0';
if(v.z[i]<100)cout<<'0';
if(v.z[i]<10)cout<<'0';
cout<<v.z[i];
}
return cout;
}
};
gaojing operator+(const gaojing &a,const gaojing &b){
gaojing c;
int l=max(a.l,b.l);
for(int i=0;i<l;i++){
c.z[i]+=a.z[i]+b.z[i];
c.z[i+1]+=c.z[i]/k;
c.z[i]%=k;
}
if(c.z[l]!=0)l++;
c.l=l;
return c;
}
gaojing operator*(const gaojing &a,const gaojing &b){
gaojing c;
int l=a.l+b.l;
for(int i=0;i<a.l;i++)
for(int j=0;j<b.l;j++){
long long v=c.z[i]+1ll*a.z[i]*b.z[i];//1ll是将a.z[i]*b.z[i]转换成长整型
c.z[i+j+1]+=v/k;
c.z[i+j]+=v%k;
}
for(int i=0;i<l;i++){
c.z[i+1]+=c.z[i]/k;
c.z[i]%=k;
}
while(l>0&&c.z[l]==0)
l--;
l++;
c.l=l;
return c;
}
int main(){
gaojing a,b;
cin>>a>>b;
cout<<a+b<<endl;
cout<<a*b<<endl;
return 0;
}
我们把十进制位中的每4~8位并在一起(笔者一般压4位,因为乘法时不会超过int的范围),然后照样加减,最后并不影响答案,但是要注意输出。对于除法,我们此时发现枚举104104到108108太慢了,注意到单调性,于是我们考虑二分试商,这样就也可以在log2BASElog2BASE的时间之内求出来了。
注意初始化、赋值和输出。
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
typedef int ll;
struct bign//big number
{
//init
static const int BASE=(int)1e4,POW=4;
static const int MAXLEN=20010;
ll num[MAXLEN];//num[0]=length of the big number
bign(int tp=0)
{
memset(num,tp,sizeof(num));
}
void clear()
{
memset(num,0,sizeof(num));
}
bool operator=(const char ch[])
{
int len=strlen(ch);
for(int i=0;i<len;i++)
num[(len-i-1)/POW+1]=num[(len-i-1)/POW+1]*10+ch[i]-'0';
num[0]=(len-1)/POW+1;
}
//compare
//big number
bool operator<(const bign &rsh)const
{
if(num[0]!=rsh.num[0])
return num[0]<rsh.num[0];
for(int i=num[0];i;i--)
{
if(num[i]!=rsh.num[i])
return num[i]<rsh.num[i];
}
return 0;
}
//int/long long
ll max(ll _x,ll _y)
{
return _x>_y?_x:_y;
}
ll min(ll _x,ll _y)
{
return _x<_y?_x:_y;
}
//operator
//add
void operator+=(const bign &rsh)
{
num[0]=max(num[0],rsh.num[0]);
for(int i=1;i<=num[0];i++)
{
num[i]+=rsh.num[i];
num[i+1]+=num[i]/BASE;
num[i]%=BASE;
}
while(num[num[0]+1]>0)
num[0]++;
}
bign operator+(const bign &rsh)const
{
bign res=*this;res+=rsh;
return res;
}
//subtract
void operator-=(const bign &rsh)
{
for(int i=1;i<=num[0];i++)
{
num[i]-=rsh.num[i];
while(num[i]<0)
{
num[i]+=BASE;
num[i+1]--;
}
}
while(num[num[0]]<=0&&num[0]>0)
num[0]--;
}
bign operator-(const bign &rsh)const
{
bign res=*this;res-=rsh;
return res;
}
//multiply
bign operator*(const bign &rsh)const
{
bign res;
res.num[0]=num[0]+rsh.num[0]-1;
for(int i=1;i<=num[0];i++)
for(int j=1;j<=rsh.num[0];++j)
res.num[i+j-1]+=num[i]*rsh.num[j];
for(int i=1;i<=res.num[0];i++)
{
res.num[i+1]+=res.num[i]/BASE;
res.num[i]%=BASE;
}
while(res.num[res.num[0]+1]>0)
{
res.num[0]++;
res.num[res.num[0]+1]+=res.num[res.num[0]]/BASE;
res.num[res.num[0]]%=BASE;
}
return res;
}
void operator*=(const bign &rsh)
{
bign res=*this;res=res*rsh;
*this=res;
}
//divide
void operator/=(const ll &rsh)
{
for(int i=num[0];i>1;i--)
{
num[i-1]+=(num[i]%rsh*BASE);
num[i]/=rsh;
}
num[1]/=rsh;
while(num[0]>0&&num[num[0]]<=0)
num[0]--;
}
bign operator/(const ll &rsh)const
{
bign temp=*this ;
temp/=rsh;
return temp;
}
void operator/=(const bign &rsh)
{
bign l,r=*this,tmp_one;tmp_one="1";
l.num[0]=1;
while(l<r)
{
bign mid=(l+r+tmp_one)/2;
if(*this<(rsh*mid))
r=mid-tmp_one;
else
l=mid;
}
*this=l;
}
bign operator/(const bign &rsh)const
{
bign res=*this;res/=rsh;
return res;
}
//mod
void operator%=(const bign &rsh)
{
bign res=*this;
res=res-res/rsh*rsh;
*this=res;
}
bign operator%(const bign &rsh)const
{
bign res=*this;res%=rsh;
return res;
}
};
ostream&operator<<(ostream &out,const bign &x)
{
printf("%d",x.num[x.num[0]]);
for(int i=x.num[0]-1;i;i--)
printf("%04d",x.num[i]);
return out;
}