• 高精度模板 支持各种运算 c++


    绪言

    自从有了高精度模板,妈妈再也不用怕我不会打高精度了!

    代码

    代码长度与日俱增啊~~~

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 #include<cmath>
      5 using namespace std;
      6 
      7 bool insigma(char ch){
      8     return ch=='-'||('0'<=ch&&ch<='9');
      9 }
     10 
     11 const int maxn = 1000;
     12 struct number{
     13     int num[maxn];
     14     int len;
     15     bool fu;
     16     
     17     number(){//初始化 
     18         len=fu=0;
     19         memset(num,0,sizeof(num));
     20     }
     21     
     22     int updata_len(){//更新长度 
     23         for(int i=maxn-1;i>=0;i--) if(num[i]) return len=i+1;
     24         return len=0;
     25     }
     26     
     27     //    /*
     28     number operator= (int x){//隐式转换 
     29         fu=(x<0);
     30         num[0]=abs(x);
     31         if(x>9) carry_bit();
     32         if(x<-9) back_space();
     33         return *this;
     34     }
     35 //    */
     36     /*
     37     number (int x){//有bug的构造函数 暂时用重载=替代 
     38         fu=(x<0);
     39         num[0]=abs(x);
     40         if(x>9) carry_bit();
     41         if(x<-9) back_space();
     42     }
     43     */
     44     
     45     void input(){
     46 //        /*
     47         string a;
     48         cin>>a;
     49         if(a[0]=='-'){
     50             fu=1;
     51             len=a.size()-1;
     52             for(unsigned int i=0;i<a.size()-1;i++) num[i]=a[a.size()-i-1]-'0';
     53         }
     54         else{
     55             len=a.size();
     56             for(unsigned int i=0;i<a.size();i++)    num[i]=a[a.size()-i-1]-'0';
     57         }
     58         
     59 //        */
     60         /*
     61         len=0;
     62         char ch;
     63         while(!insigma(ch=getchar()));
     64         if(ch=='-')
     65             fu=true;
     66         else 
     67             num[len++]=ch-'0';
     68         while(isdigit(ch=getchar())){
     69             num[len++]=ch-'0';
     70         }
     71         int t;
     72         for(int i=0;i<len;i++)
     73         {
     74             t=num[i];
     75             num[i]=num[len-i-1];
     76             num[len-i-1]=t; 
     77         }
     78         */
     79     }
     80     
     81     void output(){
     82         if(fu) cout<<"-";
     83         bool flag=0;
     84         for(int i=len;i>0;i--){
     85             if(num[i]) flag=1;
     86             if(num[i]>9) carry_bit(); 
     87             if(flag) putchar(num[i]+'0');//putchar加速 
     88         }
     89         putchar(num[0]+'0');
     90     }
     91     
     92     friend istream & operator>> (istream &in, number &obj);    
     93     friend ostream & operator<< (ostream &out, number &obj);
     94     
     95     int compare(number x){//2=    1> 0<
     96         if(fu^x.fu){
     97             if(fu) return 0; 
     98             else return 1;
     99         }
    100         for(int i=max(len,x.len);i>=0;i--)
    101         {
    102             if(num[i]>x.num[i]) return !fu;//大于 (1)
    103             if(num[i]<x.num[i]) return fu;//小于 (0)
    104         }
    105         return 2;//相等 
    106     }
    107     
    108     //利用compare()重载比较运算符 
    109      
    110     bool operator> (number x){
    111         return (compare(x)==1);
    112     } 
    113     
    114     bool operator< (number x){
    115         return (compare(x)==0);
    116     }
    117     
    118     bool operator>= (number x){
    119         return !(*this<x);
    120     }
    121     
    122     bool operator<= (number x){
    123         return !(*this>x);
    124     }
    125     
    126     bool operator== (number x){
    127         return compare(x)==2;
    128     }
    129     
    130     bool operator!= (number x){
    131         return compare(x)!=2;
    132     }
    133 
    134     number operator++ (){
    135         num[0]++;
    136         if(num[0]>9) carry_bit();
    137         return *this;
    138     }
    139     
    140     number operator++ (int){
    141         number save=*this;
    142         ++*this;
    143         return save;
    144     }
    145     
    146     number operator-- (){
    147         num[0]--;
    148         if(num[0]<0) back_space();
    149         return *this;
    150     }
    151     
    152     number operator-- (int){
    153         number save=*this;
    154         num[0]--;
    155         if(num[0]<0) back_space();
    156         return save;
    157     }
    158     
    159     bool judge_zero(){
    160         for(int i=maxn-1;i>=0;i--)
    161             if(num[i]) return 0;
    162         return 1;
    163     }
    164     
    165     bool judge_non_zero(){
    166         return !judge_zero();
    167     }
    168     
    169     bool convert_bool(){
    170         return !judge_zero();
    171     }
    172     
    173     bool even(){
    174         if(num[0]%2) return 0;
    175         return 1;
    176     }
    177     
    178     bool odd(){
    179         if(num[0]%2) return 1;
    180         return 0;
    181     }
    182     
    183     void carry_bit(){
    184         for(int i=0;i<maxn;i++){
    185             num[i+1]+=num[i]/10;
    186             num[i]%=10;
    187         }
    188         updata_len();
    189     }
    190     
    191     void back_space(){
    192         for(int i=0;i<maxn;i++){
    193             while(num[i]<0) num[i]+=10,num[i+1]--;
    194         }
    195     }
    196     
    197     number operator+ (int x){
    198         number newness=*this;
    199         newness.num[0]+=x;
    200         if(newness.num[0]>9) newness.carry_bit();
    201         return newness;
    202     }
    203     
    204     number operator+ (number x){
    205         number res=x;
    206         for(int i=0;i<maxn;i++)
    207         {
    208             res.num[i]+=num[i];
    209         }
    210         res.carry_bit();
    211         return res;
    212     }
    213     
    214     number operator+= (int x){
    215         *this=(*this+x);
    216         return *this;
    217     }
    218     
    219     number operator+= (number x){
    220         *this=*this+x;
    221         return *this;
    222     }
    223     
    224     number operator- (number x){
    225         number i,j;
    226         if(compare(x)) {i=*this,j=x;}
    227         else {i=x,j=*this;}
    228         for(int t=0;t<maxn;t++)
    229         {
    230             i.num[t]-=j.num[t];
    231         }
    232         i.back_space();
    233         return i;
    234     }
    235     
    236     number operator-= (number x){
    237         *this=*this-x;
    238         return *this; 
    239     }
    240     
    241     number operator* (number x){
    242         number sum;
    243         sum.fu=fu^x.fu;
    244         for(int i=0;i<updata_len();i++)
    245         for(int j=0;j<x.updata_len();j++)
    246         {
    247             if(i+j>maxn-1) continue;
    248             sum.num[i+j]+=num[i]*x.num[j];
    249         }
    250         sum.carry_bit();
    251         return sum;
    252     }
    253     
    254     number operator*= (number x){
    255         return *this=*this*x;
    256     }
    257     
    258     number factor(){
    259         number ans,t;
    260         t.num[0]=1;
    261         ans.num[0]=1;
    262         for(;t<=*this;t.num[0]+=1,t.carry_bit())
    263             ans*=t;
    264         return ans;
    265     }
    266     
    267     number division2(){
    268         for(int i=maxn-1;i>=0;i--){
    269             if(num[i]&1&&i!=0) num[i-1]+=10;
    270             num[i]>>=1;
    271         }
    272         return *this;
    273     }
    274 };
    275 
    276 istream & operator>> (istream &in, number &obj)
    277 {
    278     string a;
    279     in>>a;
    280     if(a[0]=='-'){
    281         obj.fu=1;
    282         obj.len=a.size()-1;
    283         for(unsigned int i=0;i<a.size()-1;i++) obj.num[i]=a[a.size()-i-1]-'0';
    284     }
    285     else{
    286         obj.len=a.size();
    287         for(unsigned int i=0;i<a.size();i++) obj.num[i]=a[a.size()-i-1]-'0';
    288     }
    289     if (!in) obj = number();
    290     return in;
    291 }
    292 
    293 ostream & operator<< (ostream &out, number &obj)
    294 {
    295     if(obj.fu) cout<<"-";
    296         bool flag=0;
    297         for(int i=obj.len;i>0;i--){
    298             if(obj.num[i]) flag=1;
    299             if(obj.num[i]>9) obj.carry_bit(); 
    300             if(flag) out<<obj.num[i]; 
    301         }
    302         out<<obj.num[0];
    303     return out;
    304 }
    305 
    306 
    307 number gcd_rec(number a,number b){
    308     if(b.judge_zero()) return a;
    309     return gcd_rec(b,a-b);
    310 }
    311 
    312 number gcd(number a,number b){
    313     if(a.judge_zero()) return a;
    314     number t;
    315     for(;;t=b,b=a-b,a=t)
    316         if(b.judge_zero()) return a;
    317     return a;
    318 }
    319 
    320 number power(number a,number n){
    321     number zero;
    322     number c;c=1;
    323     for(;n>zero;n.division2(),a*=a) if(n.odd()) c*=a;
    324     return c;
    325 }
    326 
    327 int main()
    328 {
    329     freopen("gcd.in","r",stdin);
    330     freopen("gcd.out","w",stdout);
    331     number a,b,c;
    332     cin>>a>>b;
    333     c=gcd(a,b);
    334     cout<<c;
    335     return 0;
    336 }
    折柳的高精度模板Code

    更新日志

    其实我是在写了300行以后才来写这篇博客的,所以之前的时间点就不计了吧!

    (2019-11-05ago)

    加法

    进位

    构造

    比较

    减法

    退位

    递归求gcd

    非递归gcd

    乘法

    阶乘

    iostream

    除以2

    判断奇偶

    快速幂

    ……

    细节实现

    相信这里有许多我(以前)不会的c++语言用法吧。我把它们都记录下来了呢!

    构造函数

    当我们定义一个number时,由于可能是局部变量,我们就要先将其赋初值

    但是number不是int,不是double,要是我们要赋初值的话,还得将其所有的变量(even arraies!)赋初值!

    所以我为了在使用number时方便,在网上找了个东西叫做 构造函数

    函数与结构体(或类,一下省略)同名,没有返回值(不是void!)

    在新定义一个number时会自动调用

    作用大概就是 赋初值 吧

    (PS:还有个函数叫 析构函数,用于释放结构体内存时操作(例如:删除指针等),有兴趣可以去看看)

    number(){
        len=fu=0;
        memset(num,0,sizeof(num));
    }

    但要是我们要给一个number赋初值怎么办?

    一个即将退役的老OIer告诉我,再来一个构造函数,但是它是要传参的呗!

    但是,由于我不会用,只好重载的=(赋值运算符)来赋初值。

    number operator= (int x){//隐式转换(?) 
        fu=(x<0);
        num[0]=abs(x);
        if(x>9) carry_bit();
        if(x<-9) back_space();
        return *this;
    }

    也许以后我就会用了吧!

    重载前缀自增自减运算符

    本来我想到了自增自减有前缀和后缀之分,但是不知道该怎么打……

    所以就先打了个不知道是哪种的operator+

    number operator++ (){
        num[0]++;
        if(num[0]>9) carry_bit();
        return *this;
    }

    结果发现只有前缀才能用。

    那么后缀的该怎么打呢?

    重载后缀自增自减运算符

    几番查找后,终于在《C++ Primer Plus》里面找到了

    只要在()里加一个int即可

    (原理不知)

    number operator++ (int){
        number save=*this;
        ++*this;
        return save;
    }

    这里我甚至还偷懒地在后缀里用了前缀……本来就没错嘛!

    重载赋值运算符(int转num高精度)

     见 构造函数 末尾部分

    number operator= (int x){//隐式转换 
        fu=(x<0);
        num[0]=abs(x);
        if(x>9) carry_bit();
        if(x<-9) back_space();
        return *this;
    }

    重载输入输出流运算符(友元)

    首先我为了输入输出各自写了一个成员函数

    void input(){
        string a;
        cin>>a;
        if(a[0]=='-'){
            fu=1;
            len=a.size()-1;
            for(unsigned int i=0;i<a.size()-1;i++) num[i]=a[a.size()-i-1]-'0';
        }
        else{
            len=a.size();
            for(unsigned int i=0;i<a.size();i++)    num[i]=a[a.size()-i-1]-'0';
        }
    }
    void output(){
        if(fu) cout<<"-";
        bool flag=0;
        for(int i=len;i>0;i--){
            if(num[i]) flag=1;
            if(num[i]>9) carry_bit(); 
            if(flag) putchar(num[i]+'0');//putchar加速 
        }
        putchar(num[0]+'0');
    }

    后来,我想:看看人家STL-string,都可以直接拿cin cout输入输出了,你怎么就不可以做到呢?

     我又去网上,书中找了找怎么重载流运算符……

    不想讲了,就是套模板,把之前写的那个input和output套进去就可以了嘛!

    But,由于stream是一个已经封装好了的类,你也不能修改头文件中的内容,怎么办呢?

    answer:用友元!它可以“打入敌人内部”进行一些操作!

    友元函数声明(要放在结构体中!)

    friend istream & operator>> (istream &in, number &obj);    
    friend ostream & operator<< (ostream &out, number &obj); 

    即 在正常的函数前加上friend即可

    友元函数定义(要放在全局中!)

    istream & operator>> (istream &in, number &obj)
    {
        string a;
        in>>a;
        if(a[0]=='-'){
            obj.fu=1;
            obj.len=a.size()-1;
            for(unsigned int i=0;i<a.size()-1;i++) obj.num[i]=a[a.size()-i-1]-'0';
        }
        else{
            obj.len=a.size();
            for(unsigned int i=0;i<a.size();i++) obj.num[i]=a[a.size()-i-1]-'0';
        }
        if (!in) obj = number();
        return in;
    }
    
    ostream & operator<< (ostream &out, number &obj)
    {
        if(obj.fu) cout<<"-";
            bool flag=0;
            for(int i=obj.len;i>0;i--){
                if(obj.num[i]) flag=1;
                if(obj.num[i]>9) obj.carry_bit(); 
                if(flag) out<<obj.num[i]; 
            }
            out<<obj.num[0];
        return out;
    }

    重载判断符运算符

    那么多比较函数,我一下子那写的过来呢?

    本来我都是没有operator这些比较运算符的,只用了一个int compare(number)就好了

    PS:为什么返回值不是bool而是int呢?因为返回的信息可能不只有大于,小于,还会有等于呀!

    int compare(number x){//2=    1> 0<
        if(fu^x.fu){
            if(fu) return 0; 
            else return 1;
        }
        for(int i=max(len,x.len);i>=0;i--)
        {
            if(num[i]>x.num[i]) return !fu;//大于 (1)
            if(num[i]<x.num[i]) return fu;//小于 (0)
        }
        return 2;//相等 
    }

    后来,我觉得这样十分的不直观,而且有时容易错,还是个成员函数,调用时是a.compare(b)这样的形式的……

    所以我就把"<",">","<=",">=","==","!="都重载了!

    Impression

    现在的长度是有限的而且在枚举时也可能会有大量时间浪费

    尽管已经引进了len和updata_len(),但是这两个玩意的作用还是较小,用法比较麻烦

    希望能像STL的某些容器那样可自动改变大小,已经O(1)就可以知道number的位数

    不知道为什么,一个number表达式不可以用cout<<输出?

    就像

    a,b为number时,cout<<(a+b);不可以;

    但是

    a,b为int时,cout<<(a+b);可以!

    是因为operator<< 里的参数obj为引用吗?

    除法(二分)

    这个玩意还有存在许多许多可以更新&改进的地方,欢迎提建议!

  • 相关阅读:
    调试一个 Bus error 错误
    推荐10个我在用的Chrome浏览器插件
    六个让你的Ubuntu系统提速的方法
    6个可以隐藏运行bat,浏览器等程序的方法
    Windows下5个简单快速加密文件的方法
    如何获取与安装你需要的android 应用
    一款免费的.NET智能持续测试运行工具——MightyMoose
    给 mysql 系统表加上 trigger
    2011百度数据挖掘研发工程师实习生笔试面试题
    Linux常用操作命令整理
  • 原文地址:https://www.cnblogs.com/send-off-a-friend/p/11746431.html
Copyright © 2020-2023  润新知