高精度计算

高精度计算

当我们计算天文数字时,int 就不够用了(-2147483648~2147483647)(10位),long long 有时也不够用(-9223372036854775808~9223372036854775807)(20位)

而高精度计算就是来解决这类问题

问题:现有数据类型无法存储20位以上的数字,我们就用到数组存储,要选择正序还是倒序呢?

           如果选择正序,例如a[0] 为最高位,a[1] 为次高位,等到我们进位时,就没法存储了。

           因为数组是可以往后延伸,所以我们使用倒序存储

void in()
{
  memset(a,0,sizeof(a));//初始化  
  cin>>str1; //一次输入字符串 
  a[0]=str1.length();//a[0]空缺,减少变量,存长度
  for(i=1;i<=a[0];i++)  
    a[i]=str1[a[0]-i]-'0';//字符转int  
}

存储的问题解决了,那么如何进行运算呢?

模拟大法好

加法:对应位相加,满10进1

减法:比较被减数与减数,确定答案正负号,大减小

乘法:两个数的每一位与每一位相乘,累计到i+j-1位,满10进1

加法

#include<iostream>
#include<cstring>
#define N 10010
using namespace std;
string str1,str2;
int a[N],b[N],len,i;
void in()
{
   memset(a,0,sizeof(a));  //初始化
   memset(b,0,sizeof(b));
   cin>>str1>>str2; 
   a[0]=str1.length();  //在a数组中只用了1-....用a[0]存长度减少变量
   b[0]=str2.length();
   for(i=1;i<=a[0];i++)
      a[i]=str1[a[0]-i]-'0'; //字符串转数组,运算
   for(i=1;i<=b[0];i++)
      b[i]=str2[b[0]-i]-'0'; //倒序存储,方便进位
}
void add()
{
   len=(a[0]>b[0]?a[0]:b[0]); //三目运算符
   for(i=1;i<=len;i++)
     {
       a[i]+=b[i]; //对应位置相加
       a[i+1]+=a[i]/10; //进位
       a[i]%=10; 
      }
       len++; //防止最高位进位
}
void out()
{
   while((a[len]==0)&&(len>1)) len--; //去前导零,防止最高位为零
   for(i=len;i>=1;i--)
      cout<<a[i];
}
int main()
{
   in();
   add();
   out();
}
加法

减法

#include<iostream>
#include<cstring>
#define N 100000
using namespace std;
string str1,str2;
int a[N],b[N],len,i;
int compare(string s1,string s2) //判断两数大小
{
    if(s1.length()>s2.length()) return 0; //先比长度
    if(s1.length()<s2.length()) return 1;
    for(int i=0;i<=s1.length();i++) //再从最高位开始判断
      {
         if(s1[i]>s2[i]) return 0;
         if(s1[i]<s2[i]) return 1;
      }
    return 0; //如果一样返回零
}
void in()
{
  memset(a,0,sizeof(a));
  memset(b,0,sizeof(b));
  cin>>str1>>str2;
  a[0]=str1.length();
  b[0]=str2.length();
  for(i=1;i<=a[0];i++)
      a[i]=str1[a[0]-i]-'0'; 
  for(i=1;i<=b[0];i++)  
      b[i]=str2[b[0]-i]-'0';
}
void sub()
{
   if((compare(str1,str2))==0)//s1>s2,结果为正
     {
       for(i=1;i<=a[0];i++)
         {     
           a[i]-=b[i];//对应位相减
           if(a[i]<0)//借位
             {a[i+1]--;a[i]+=10;}
         }
        a[0]++;//防止进位
        while((a[a[0]]==0)&&(a[0]>1)) a[0]--;//去前导零
        for(i=a[0];i>=1;i--)
           cout<<a[i];
           cout<<endl;
      }
   else
     {
       cout<<'-';//s1<s2,答案为负
       for(i=1;i<=b[0];i++)
         {
           b[i]-=a[i];
           if(b[i]<0) 
            {b[i+1]--;b[i]+=10;} 
          }
       b[0]++;
       while((b[b[0]]==0)&&(b[0]>1)) b[0]--;
       for(i=b[0];i>=1;i--)
         cout<<b[i];
         cout<<endl;
     }
}

int main()
{
   in();
   sub();
}
减法

乘法

#include<iostream>
#include<cstring>
#define N 1000000
using namespace std;
string str1,str2;
int a[N],b[N],c[N],len;
int i,j;
void in()
{
   memset(a,0,sizeof(a));
   memset(b,0,sizeof(b));       
   memset(c,0,sizeof(c));         
   cin>>str1>>str2; 
   a[0]=str1.length();
   b[0]=str2.length();
   for(i=1;i<=a[0];i++)
      a[i]=str1[a[0]-i]-'0';
   for(i=1;i<=b[0];i++)
      b[i]=str2[b[0]-i]-'0';
}
void mul()
{
  for(i=1;i<=a[0];i++)
    for(j=1;j<=b[0];j++)
      {
        c[i+j-1]+=a[i]*b[j];//对应位相乘
        c[i+j]+=c[i+j-1]/10;//进位
        c[i+j-1]%=10;
      }
}
void out()
{
  len=a[0]+b[0]+1;
  while((c[len]==0)&&(len>1)) len--;
  for(i=len;i>=1;i--)
    cout<<c[i];
}
int main()
{
   in();
   mul();
   out();
}
乘法

单精除

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 100100
using namespace std;
char s[N];
int a[N],b;
int main()
{
  int la,b;
  cin>>s>>b;
  la=strlen(s);
  for (int i=1;i<=la;i++)
     a[i]=s[la-i]-48;
  int d,r=0;
  for (int i=la;i>=1;i--)
     {
       d=r*10+a[i];
       a[i]=d/b;
       r=d%b;
      }
  while(a[la]==0)  la--;//处理最高位
         
  for(int i=la;i>=1;i--)
     cout<<a[i];
     cout<<endl;
}
单精除

2^n

#include<iostream>
#include<cstring>
#define N 50
using namespace std;
int a[N],n,lena=1;
int main()
{
    cin>>n;
    a[0]=1;
    while(n--)
    {
       for(int i=0;i<lena;i++)a[i]*=2;
       for(int i=0;i<lena;i++)
           {
              if(a[i]>9)
                {
                   a[i+1]++;
                   a[i]-=10;               
                   if(i==lena-1)lena++;
                 }           
           }     
    }
    for(int i=lena-1;i>=0;i--)cout<<a[i];
    cout<<endl;
} 
2^n

阶乘和

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
int a[40000]={1},ans[40000]={1};
int b,t,la=1,lans=1;
void jiecheng(int j)
{
    b=0;
    for(int k=0;k<la;k++)  
    {
        t=a[k]*j+b;
        b=t/10;                
        a[k]=t%10;          
    }
    while(b>0)       
        {
            a[la++]+=b%10;
            b/=10;
        }

}
void add()
{
    int x=0;
    lans=lans>la?lans:la;   
    for(int i=0;i<lans;i++) 
    {
        ans[i]=ans[i]+a[i]+x;  
        x=ans[i]/10;
        ans[i]%=10;
    }
    if(x>0)   
    {
        ans[lans++]=x;
    }
}

int main()
{
    int n;
    cin>>n;
    for(int i=2;i<=n;i++)//先算阶乘后相加
    {
        jiecheng(i);   
        add(); 
    }
    while(ans[lans]==0)//去前导零
    {
        lans--;  
    }
    for(int i=lans;i>=0;i--)  
    {
        cout<<ans[i];
    }
    return 0;
}
阶乘和

10000内的阶乘

#include<iostream>
#include<cstring>
#define N 100010
using namespace std;
int n,a[N],lena=1;
int main()
{
    cin>>n;
    a[0]=1;
    for(int k=2;k<=n;k++)
    {
        for(int i=0;i<lena;i++) a[i]*=k;
        for(int i=0;i<lena;i++)
        {
            if(a[i]>9)
            {
                a[i+1]+=a[i]/10;
                a[i]%=10;
                if(i==lena-1)lena++;
            }
         }
     }
    for(int i=lena-1;i>=0;i--)cout<<a[i];
    cout<<endl;
}
阶乘

重载运算符

#include <cstdio>
#include <string>
#include<iostream>
#include<algorithm>
#include<cstring>
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
struct Data
{
    int a[100001],len;//存储每位数的数组和长度 
    
    Data()//初始值
    {
        memset(a, 0, sizeof(a));
        len = 1;
    }
    
    void read()//读入函数
    {
        char d[100001];
        scanf("%s",d);
        int l=strlen(d);
        for(int i=1; i<=l; i++)
            a[i]=d[l-i]-'0';//倒序存储,方便进位 
        len=l;//记录长度 
    }
    
    void write()//输出函数
    {
        for(int i = len; i>=1; i--)
            printf("%d", a[i]);//倒序输出 
    }
    
    void clean()//去掉前导零 
    {
        while (len>1&&!a[len]) len--;
    }
    
    friend bool operator < (const Data &A,const Data & B)
     //可以定义在外,外面请不要加friend;在内部不加friend,不能用两个参数 
    {//const防止你改值,别忘了取地址 & 
        if(A.len>B.len) return 0; //先比长度
        if(A.len<B.len) return 1;
        for(int i=1;i<=A.len;i++) //再从最高位开始判断
        {
         if(A.a[i]>B.a[i]) return 0;
         if(A.a[i]<B.a[i]) return 1;
        }
        return 0; //如果一样返回零
    }
    
    friend bool operator <= (const Data & A,const Data & B)
    {
        if(A.len>B.len) return 0; 
        if(A.len<B.len) return 1;
        for(int i=1;i<=A.len;i++) 
        {
         if(A.a[i]>B.a[i]) return 0;
         if(A.a[i]<B.a[i]) return 1;
        }
        return 1; //如果一样返回 1
    }
    
    friend bool operator > (const Data & A,const Data & B)
    {
        if(A.len>B.len) return 1; 
        if(A.len<B.len) return 0;
        for(int i=1;i<=A.len;i++) 
        {
         if(A.a[i]>B.a[i]) return 1;
         if(A.a[i]<B.a[i]) return 0;
        }
        return 0;
    }
    
    friend bool operator >= (const Data & A,const Data &B)
    {
        if(A.len>B.len) return 1; 
        if(A.len<B.len) return 0;
        for(int i=1;i<=A.len;i++) 
        {
         if(A.a[i]>B.a[i]) return 1;
         if(A.a[i]<B.a[i]) return 0;
        }
        return 1;
    }
    friend bool operator == (const Data & A,const Data &B)
    {
        if(A.len>B.len) return 0; 
        if(A.len<B.len) return 0;
        for(int i=1;i<=A.len;i++) 
        {
         if(A.a[i]>B.a[i]) return 0;
         if(A.a[i]<B.a[i]) return 0;
        }
        return 1;//长度相等,对应位数相等才相等 
    }

    friend Data operator + (const Data &A,const Data &B)
    {
        Data C;//因为A,B均不可以改值,所以引入C,C长度1,值为0 
        C.len = max(B.len, A.len);//选取A,B长度最大的 
        for(int i = 1 ; i <= C.len; i++)//边界需要注意
        {
            C.a[i] += A.a[i]+B.a[i];//对应位相加 
            if(C.a[i] >= 10)//每十进一 
            {
                C.a[i] -= 10;
                //由于不会超过10,故用 -=10 代替 %10 效率更高
                C.a[i+1]++;//进位
            }
        }
        if(C.a[C.len+1])//考虑是否会进到B.len的下一位
            C.len++;
        C.clean();//去0,即使长度大了也不要紧 
        return C;
    }
    
    friend Data operator - (const Data &A ,const Data &B)
    {
        Data C;//因为A,B均不可以改值,所以引入C,C长度1,值为0
        if( A > B)
        {
            C.len=A.len;
            for(int i=1;i<=A.len;i++)
                {     
                    C.a[i]+=A.a[i]-B.a[i];
                    if(C.a[i]<0)//借位
                    {C.a[i+1]--;C.a[i]+=10;}
                }
            if(C.a[C.len+1]) C.len++;
            C.clean();
            return C;
        }
        else if(A==B)//防止出现1-1=-0的情况 
        {
            return C;//C的初始长度为1,值为0 
        }
        else if (A<B)
        {
            cout<<'-';
            C.len=B.len;
            for(int i=1;i<=B.len;i++)
            {
                C.a[i]+=B.a[i]-A.a[i];
                if(C.a[i]<0) 
                {C.a[i+1]--;C.a[i]+=10;} 
            }
            if(C.a[C.len+1]) C.len++;
            C.clean();
            return C;
        }
    }
    
    friend Data operator * (const Data &A ,const Data &B)
    {
        Data C;
        C.len=A.len+B.len;
        //C的长度最大为 A.len+B.len,有时 A.len+B.len-1
        for(int i=1;i<=A.len;i++)
            for(int j=1;j<=B.len;j++)
                {
                    C.a[i+j-1]+=A.a[i]*B.a[j];
                //相乘结果加在i+j-1上 
                    C.a[i+j]+=C.a[i+j-1]/10;
                    C.a[i+j-1]%=10;
                }
        if(C.a[C.len+1]) C.len++;
        C.clean();
        return C;  
    }
    
};

Data A,B,C;
int main()
{
    A.read();
    B.read();
    C = A+B;
    //C=A-B;
    //C=A*B;
    C.write();
    return 0;
}
重载运算符

 

posted @ 2020-03-10 18:02  蒟蒻WZY  阅读(150)  评论(0)    收藏  举报