大数处理模板

版权声明:本博客内容基本为原创,如有问题欢迎联系,未经允许请勿转载 https://blog.csdn.net/qq_41955236/article/details/82014593
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
#define N 400//1000位大数
using namespace std;
class BigNum
{
  public:
    int s[N];  //存放各位数字,s[0]为符号位,1代表正数,-1代表负数
               //数组内高位存高位,123存在里面则为 1 3 2 1 ,第1个 1表示符号
    int len;   //长度
  public:
    BigNum()
    {
      memset(s,0,sizeof(s));  //初始化全0
      s[0]=1;                 //默认正数
      len=2;                  //变量初始化为0
    }
    int in()              //输入
    {
      char tmp[N];
      int flag=scanf("%s",tmp);
      *this=tmp;
      return flag;
    }
    void out()            //输出
    {
      if(s[0]==-1) printf("-");
      for(int i=len-1;i>0;i--)
        printf("%d",s[i]);
    }
    void Clear()
    {
      memset(s,0,sizeof(s));  //初始化全0
      s[0]=1;                 //默认正数
      len=2;                  //变量初始化为0
    }
    BigNum Nizhi()            //排除符号位颠倒数组
    {
      BigNum ans;
      ans.s[0]=s[0];
      for(int i=1;i<=len/2;i++)
      {
        ans.s[i]=s[len-i];
        ans.s[len-i]=s[i];
      }
      ans.len=len;
      return ans;
    }
    friend bool operator<(const BigNum &a,const BigNum &b);
    friend bool operator>(const BigNum &a,const BigNum &b);
    friend bool operator<=(const BigNum &a,const BigNum &b);
    friend bool operator>=(const BigNum &a,const BigNum &b);
    friend BigNum operator+(BigNum a,BigNum b);
    friend void operator+=(BigNum &a,BigNum b);
    friend BigNum operator-(BigNum a,BigNum b);
    friend void operator-=(BigNum &a,BigNum b);
    friend BigNum operator*(BigNum a,BigNum b);
    friend void operator*=(BigNum &a,BigNum b);
    friend BigNum operator/(BigNum a,BigNum b);
    friend void operator/=(BigNum &a,BigNum b);
    friend BigNum operator%(BigNum &a,BigNum b);
    friend void operator%=(BigNum &a,BigNum b);
    friend bool operator==(const BigNum &a,const BigNum &b);
    void operator=(const int a);
    void operator=(const char *a);
    BigNum operator--();
    BigNum operator--(int);
    BigNum operator++();
    BigNum operator++(int);
};
/////////////////////////////////////////////////////////////////逻辑//////////////////
bool operator<(const BigNum &a,const BigNum &b)
{
  bool flag;
  if(a.s[0]==-1&&b.s[0]==1) return 1;      //如果a为负,b为正,那么a<b
  else if(a.s[0]==1&&b.s[0]==-1) return 0; //如果a为正,b为负,那么a>b
  else if(a.s[0]==1&&b.s[0]==1) flag=1;    //如果a、b都为正,flag=1,表示a、b大小和符号无关
  else flag=0;                             //如果a、b都为负,flag=0,表示a、b大小和符号有关
  // flag=1 时,a、b大小和除符号外的数字大小成正比,反之反比
  if(a.len>b.len) return !flag; //a的位数多,所以a大,返回0
  else if(a.len<b.len) return flag; //a的位数少,所以a小,返回1
  else
  {
    int i=a.len;                    //从最高位开始比
    while(i-->1)
    {
      if(a.s[i]>b.s[i]) return !flag;
      else if(a.s[i]<b.s[i]) return flag;
    }
    return 0;                       //没有差异即相等返回0
  }
}
bool operator<=(const BigNum &a,const BigNum &b) //同 <
{
  bool flag; // flag=1 表示两者都是正的 =0表示两者都是负的
  if(a.s[0]==-1&&b.s[0]==1) return 1;
  else if(a.s[0]==1&&b.s[0]==-1) return 0;
  else if(a.s[0]==1&&b.s[0]==1) flag=1;
  else flag=0;
  // flag 表示1 ,!flag 表示0
  if(a.len>b.len) return !flag;
  else if(a.len<b.len) return flag;
  else
  {
    int i=a.len;
    while(i-->1)
    {
      if(a.s[i]>b.s[i]) return !flag;
      else if(a.s[i]<b.s[i]) return flag;
    }
    return 1;
  }
}
bool operator>(const BigNum &a,const BigNum &b)
{
  return !(a<=b);
}
bool operator>=(const BigNum &a,const BigNum &b)
{
  return !(a<b);
}
 bool operator==(const BigNum &a,const BigNum &b)
{
  if(a.s[0]==-1&&b.s[0]==1) return 0;
  else if(a.s[0]==1&&b.s[0]==-1) return 0;
  if(a.len>b.len) return 0;
  else if(a.len<b.len) return 0;
  else
  {
    int i=a.len;
    while(i-->1)
    {
      if(a.s[i]>b.s[i]) return 0;
      else if(a.s[i]<b.s[i]) return 0;
    }
    return 1;
  }
}
///////////////////////////////////////////////////////运算///////////////
BigNum operator-(BigNum a,BigNum b)
{
  BigNum ans;
  if(a.s[0]==1&&b.s[0]==-1)      //如果a正,b负,那么等同于a+|b|
  {
    b.s[0]=1;
    return a+b;
  }
  else if(a.s[0]==-1&&b.s[0]==1) //如果a负,b正,那么等同于-(|a|+b)
  {
    a.s[0]=1;
    ans=a+b;
    ans.s[0]=-1;
    return ans;
  }
  else if(a.s[0]==-1&&b.s[0]==-1) //如果a负,b负,那么等同于|b|-|a|
  {
    a.s[0]=1;
    b.s[0]=1;
    return b-a;
  }
  else             //进到这一区域的,a为正,b为正
  {
    if(a<b)        //如果a<b,那么等同于-(b-a)
    {
      ans=b-a;
      ans.s[0]=-1;
    }
    else           //进到这一区域a、b为正,且a>b,也就是说减出来的绝对是正数
    {
      int i=0;
      int lm=a.len>b.len?a.len:b.len;  //由于减出来必定是正数,不需要考虑lm-1位<0的情况
      for(int i=1;i<lm;i++)
      {
        int tmp=ans.s[i]+a.s[i]-b.s[i];
        if(tmp<0)
        {
          ans.s[i+1]--;
          tmp+=10;
        }
        ans.s[i]=tmp;
      }
      while(lm>2)    //清楚高位0,最多清楚到0为止
      {
        if(ans.s[lm-1]==0) lm--;
        else break;
      }
      ans.len=lm;
    }
  }
  return ans;
}
void operator-=(BigNum &a,BigNum b)
{
  a=a-b;
}
BigNum operator+(BigNum a,BigNum b)
{
  BigNum ans;
  int lm=a.len>b.len?a.len:b.len;
  if(a.s[0]*b.s[0]==1)   //如果两者符号位相同
  {
    ans.s[0]=a.s[0];     //结果符号位与任意一个相同
    for(int i=1;i<lm;i++)
    {
      int tmp=ans.s[i]+a.s[i]+b.s[i];
      if(tmp>=10)
      {
        ans.s[i+1]++;
      }
      ans.s[i]=tmp%10;
    }
    if(ans.s[lm]==0) ans.len=lm; //如果最高位没有进位,那么长度不变,否则加1
    else ans.len=lm+1;
  }
  else                           //如果a、b符号不同,可以转化为减法
  {
    if(a.s[0]==1)
    {
      b.s[0]=1;
      return a-b;
    }
    else
    {
      a.s[0]=1;
      return b-a;
    }
  }
  return ans;
}
void operator+=(BigNum &a,BigNum b)
{
  a=a+b;
}

BigNum operator*(BigNum a,BigNum b)
{
  BigNum ans;
  ans.s[0]=a.s[0]*b.s[0];           //乘法和除法的符号位简单处理
  for(int i=1;i<a.len;i++)
  {
    for(int j=1;j<b.len;j++)
    {
      ans.s[i+j-1]+=a.s[i]*b.s[j];  //先存
    }
  }
  int maxt=a.len+b.len;             //最多位数
  for(int i=1;i<maxt;i++)           //处理每个位上的数
  {
    if(ans.s[i]>=10)
    {
      ans.s[i+1]+=ans.s[i]/10;
      ans.s[i]=ans.s[i]%10;
    }
  }
  int i;
  for(i=maxt;i>1;i--)               //处理高位0
  {
    if(ans.s[i]!=0) break;
  }
  ans.len=i+1;
  return ans;
}
void operator*=(BigNum &a,BigNum b)
{
  a=a*b;
}
BigNum operator/(BigNum a,BigNum b)
{
  /*
    思路: 首先从a的高位往低位数,如果还<b,那么就再加1位,知道>=b,然后遍历1-9,判断此时
        合适取值,和平常手动计算思路一样
  */
  BigNum ans;
  ans.s[0]=a.s[0]*b.s[0];
  b.s[0]=1;       //中途比较需要
  BigNum tmp;     //添位取值
  tmp.len=1;      //刚开始为无值,就是说连a的最高位都还没纳入
  BigNum zj;      //中间变量,比较时需要,由于数组是倒置的,所以加这一变量
  ans.len=1;      //答案还是空的
  int j=a.len;    //j固定指向a,不断取值
  bool match=1;   //match为0退出循环
  while(1)
  {
    while(1)   //如果还没取够值,就继续加位
    {
      if(j==1)    //如果a到了符号位,那么可以退出循环了
      {
        match=0;
        break;
      }
      tmp.s[tmp.len++]=a.s[--j]; //加位,由于开始不好确定位数,所以直接正向不好办
      zj=tmp.Nizhi();            //数组颠倒后再去比较
      if(b<=zj) break;           //如果b<=zj了,就可以退出了,否则该位为0
      ans.s[ans.len++]=0;
    }
    if(!match) break;            //match为0退出循环
    int i;
    BigNum r=b;                  //r为最大容许的乘后值
    for(i=2;i<=10;i++)
    {
      BigNum p;
      p.s[p.len-1]=i;    //获得 2 - 10 . 赋值过程不符常规,但由于下一步是乘,可以忽略该bug
      BigNum u=b*p;      //如果u超过了中间变量,可以退出了,同i应该减1
      if(zj<u) break;
      r=u;               //乘得的最大数
    }
    i--;
    ans.s[ans.len++]=i;          //逐位求值
    zj=zj-r;                     //获得余数
    BigNum q;
    if(zj==q) zj.len--;          //如果余数为0,那么去掉,不能出现00,不然会出错
    tmp=zj.Nizhi();              //重新逆置
  }
  ans=ans.Nizhi();               //逆置获得答案
  while(ans.s[ans.len-1]==0&&ans.len>2) //高位消0
  {
    ans.len--;
  }
  return ans;
}
void operator/=(BigNum &a,BigNum b)
{
  a=a/b;
}
BigNum operator%(BigNum &a,BigNum b)
{
  b.s[0]=1;
  BigNum tmp;
  tmp.len=1;
  BigNum zj;
  int j=a.len;
  bool match=1;
  while(1)
  {
    while(1)
    {
      if(j==1)
      {
        match=0;
        break;
      }
      tmp.s[tmp.len++]=a.s[--j];
      zj=tmp.Nizhi();
      if(b<=zj) break;
    }
    if(!match) break;
    int i;
    BigNum r=b;
    for(i=2;i<=10;i++)
    {
      BigNum p;
      p.s[p.len-1]=i;
      BigNum u=b*p;
      if(zj<u) break;
      r=u;
    }
    i--;
    zj=zj-r;
    BigNum q;
    if(zj==q) zj.len--;
    tmp=zj.Nizhi();
  }
  if(zj.len==1)
  {
    zj.Clear();
  }
  return zj;
}
void operator%=(BigNum &a,BigNum b)
{
  a=a%b;
}
//////////////////////////////////////////////////赋值///////////////////
void BigNum::operator=(int a)
{
  Clear();
  if(a<0)
  {
    s[0]=-1;
    a=-a;
  }
  len=1;
  while(a)
  {
    s[len++]=a%10;
    a/=10;
  }
}
void BigNum::operator=(const char *a)
{
  Clear();
  if(*a=='-')
  {
    s[0]=-1;
    a++;
  }
  len=1;
  while(*a&&*a=='0') a++;
  while(*a)
  {
    s[len++]=*a-'0';
    a++;
  }
  if(len==1) len=2;
  *this=Nizhi();
}
BigNum BigNum::operator--()   //  --a;
{
  BigNum tmp;
  tmp=-1;
  *this+=tmp;
  return *this;
}
BigNum BigNum::operator--(int)  // a--;
{
  BigNum ans;
  ans=*this;
  BigNum tmp;
  tmp=-1;
  *this+=tmp;
  return ans;
}
BigNum BigNum::operator++()  // ++a;
{
  BigNum tmp;
  tmp=1;
  *this+=tmp;
  return *this;
}
BigNum BigNum::operator++(int)  // a++;
{
  BigNum ans;
  ans=*this;
  BigNum tmp;
  tmp=1;
  *this+=tmp;
  return ans;
}

BigNum swift(BigNum a,int b){
    BigNum ans;ans=1;
    while(b){
        if(b%2)ans=ans*a;
        b>>=1;
        a=a*a;
    }return ans;
}

int main(){
    BigNum a,b;b=2;
    int t;scanf("%d",&t);
    while(t--){int n;scanf("%d",&n);
        a=swift(b,n);
        a.out();
        printf("\n");
    }
}

用了队友打比赛时候的代码。觉得自己也应该备一份,挺有用的。

猜你喜欢

转载自blog.csdn.net/qq_41955236/article/details/82014593