• 模拟:高精度


    为什么本文的标题要强调十进制形式呢?因为还有万进制的高精度,比十进制要快很多

    那我们直接掌握万进制不就好了嘛。。其实不然,十进制高精度的实现是最直接的对加减乘除的模拟,并且其中的实现方法也是值得去借鉴的

    这里在刘汝佳代码的基础上进行了一定的改进,经过了若干次测试形成了稳定版本,在对效率要求比较高的情况下,建议替换为万进制高精度

    首先给出结构体中的元素:

        int len,s[maxn];
        bign()  //构造函数
        {
            len=1;
            memset(s,0,sizeof(s));
        }

    注意,这里的s数组是倒着存数字的,为了便于计算

    接下来我们罗列几个运算符重载和工具函数,目的在注释中体现:

        bign(const int num)  //bign x=100;
        {
            *this=num;
        }
        bign(const char* num)  //bign x="100";
        {
            *this=num;
        }
        bign operator =(const int num)  //x=1234;
        {
            char s[maxn];
            sprintf(s,"%d",num);
            *this=s;
            return *this;
        }
        bign operator =(const char* num)  //x="1234";
        {
            len=strlen(num);
            for(int i=0;i<len;i++)
            s[i]=num[len-i-1]-'0';
            return *this;
        }
        string str() const  //成员函数,用于输出
        {
            string res="";
            for(int i=0;i<len;i++)
            res=(char)(s[i]+'0')+res;
            if(res=="") res="0";
            return res;
        }
        void clean()  //成员函数,用于清除前导0
        {
            while(len>1&&!s[len-1])  //当前长度>1并且当前位是0
            len--;
        }

    紧接着是加减法的实现,他们放在一起是因为他们都包含一个变量g,这里的g用来表示进位或者是借位的位数

        bign operator +(const bign& b) const
        {
            bign c;
            c.len=0;
            for(int i=0,g=0;g||i<max(len,b.len);i++)
            {
                int x=g;
                if(i<len) x+=s[i];
                if(i<b.len) x+=b.s[i];
                c.s[c.len++]=x%10;
                g=x/10;
            }
            return c;
        }
        bign operator -(const bign& b) const
        {
            bign c;
            c.len=0;
            for(int i=0,g=0;i<len;i++)
            {
                int x=s[i]-g;
                if(i<b.len) x-=b.s[i];
                if(x>=0) g=0;
                else
                {
                    g=1;
                    x+=10;
                }
                c.s[c.len++]=x;
            }
            c.clean();
            return c;
        }

    然后是乘法,掌握乘法只要掌握两个乘数和积之间下标的关系就好了(s[i+j])

        bign operator *(const bign& b) const
        {
            bign c;
            c.len=len+b.len;  //最大总位数
            for(int i=0;i<len;i++)
            for(int j=0;j<b.len;j++)
            c.s[i+j]+=s[i]*b.s[j];  //枚举出每一位
            for(int i=0;i<c.len-1;i++)
            {
                c.s[i+1]+=c.s[i]/10;  //进位
                c.s[i]%=10;  //当前位
            }
            c.clean();
            return c;
        }

    然后我们罗列一些比较运算符的重载,除法搁在后面的原因是要用到这些重载形式,比较大小的重载逻辑是显然的。

        bool operator <(const bign& b) const
        {
            if(len!=b.len) return len<b.len;  //先比位数
            for(int i=len-1;i>=0;i--)  //
            if(s[i]!=b.s[i]) return s[i]<b.s[i];  //再比最高位
        }
        bool operator >(const bign& b) const
        {
            if(len!=b.len) return len>b.len;  //先比位数
            for(int i=len-1;i>=0;i--)  //
            if(s[i]!=b.s[i]) return s[i]>b.s[i];  //再比最高位
        }
        bool operator ==(const bign& b) const
        {
            return !(*this>b)&&!(*this<b);
        }
        bool operator >=(const bign& b) const
        {
            return *this>b||*this==b;
        }

    对于除法的重载,我们采用的是一位一位减,当然可以使用二分法,二分法的形式后期可能会加以补充

        bign operator /(const bign &b) const
        {
            bign c,f=0;
            for(int i=len-1;i>=0;i--)
            {
                f=f*10;
                f.s[0]=s[i];
                while(f>=b)
                {
                    f=f-b;
                    c.s[i]++;
                }
            }
            c.len=len;
            c.clean();
            return c;
        }

    接下来重载<<和>>运算符来支持cin和cout

    istream &operator >>(istream &in,bign& x)  //重载输入
    {
        string s;
        in>>s;
        x=s.c_str();
        return in;
    }
    ostream & operator <<(ostream & out,const bign& x)  //重载输出
    {
        out<<x.str();
        return out;
    }

    最后给出完整模板,大部分的题目都要求结果去模一个数,高精度的用武之地很少了,只能出现在OI的部分分中,ACM中很少出现

    除非将一些类似于表达式求值或者是矩阵快速幂等一些复杂的模拟形式与之相结合。。。

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 #include<cstdlib>
      5 #include<string>
      6 using namespace std;
      7 const int maxn=505;
      8 struct bign
      9 {
     10     int len,s[maxn];
     11     bign()  //构造函数
     12     {
     13         len=1;
     14         memset(s,0,sizeof(s));
     15     }
     16     bign(const int num)  //bign x=100;
     17     {
     18         *this=num;
     19     }
     20     bign(const char* num)  //bign x="100";
     21     {
     22         *this=num;
     23     }
     24     bign operator =(const int num)  //x=1234;
     25     {
     26         char s[maxn];
     27         sprintf(s,"%d",num);
     28         *this=s;
     29         return *this;
     30     }
     31     bign operator =(const char* num)  //x="1234";
     32     {
     33         len=strlen(num);
     34         for(int i=0;i<len;i++)
     35         s[i]=num[len-i-1]-'0';
     36         return *this;
     37     }
     38     string str() const  //成员函数,用于输出
     39     {
     40         string res="";
     41         for(int i=0;i<len;i++)
     42         res=(char)(s[i]+'0')+res;
     43         if(res=="") res="0";
     44         return res;
     45     }
     46     void clean()  //成员函数,用于清除前导0
     47     {
     48         while(len>1&&!s[len-1])  //当前长度>1并且当前位是0
     49         len--;
     50     }
     51     bign operator +(const bign& b) const
     52     {
     53         bign c;
     54         c.len=0;
     55         for(int i=0,g=0;g||i<max(len,b.len);i++)
     56         {
     57             int x=g;
     58             if(i<len) x+=s[i];
     59             if(i<b.len) x+=b.s[i];
     60             c.s[c.len++]=x%10;
     61             g=x/10;
     62         }
     63         return c;
     64     }
     65     bign operator -(const bign& b) const
     66     {
     67         bign c;
     68         c.len=0;
     69         for(int i=0,g=0;i<len;i++)
     70         {
     71             int x=s[i]-g;
     72             if(i<b.len) x-=b.s[i];
     73             if(x>=0) g=0;
     74             else
     75             {
     76                 g=1;
     77                 x+=10;
     78             }
     79             c.s[c.len++]=x;
     80         }
     81         c.clean();
     82         return c;
     83     }
     84     bign operator *(const bign& b) const
     85     {
     86         bign c;
     87         c.len=len+b.len;  //最大总位数
     88         for(int i=0;i<len;i++)
     89         for(int j=0;j<b.len;j++)
     90         c.s[i+j]+=s[i]*b.s[j];  //枚举出每一位
     91         for(int i=0;i<c.len-1;i++)
     92         {
     93             c.s[i+1]+=c.s[i]/10;  //进位
     94             c.s[i]%=10;  //当前位
     95         }
     96         c.clean();
     97         return c;
     98     }
     99     bool operator <(const bign& b) const
    100     {
    101         if(len!=b.len) return len<b.len;  //先比位数
    102         for(int i=len-1;i>=0;i--)  //
    103         if(s[i]!=b.s[i]) return s[i]<b.s[i];  //再比最高位
    104     }
    105     bool operator >(const bign& b) const
    106     {
    107         if(len!=b.len) return len>b.len;  //先比位数
    108         for(int i=len-1;i>=0;i--)  //
    109         if(s[i]!=b.s[i]) return s[i]>b.s[i];  //再比最高位
    110     }
    111     bool operator ==(const bign& b) const
    112     {
    113         return !(*this>b)&&!(*this<b);
    114     }
    115     bool operator >=(const bign& b) const
    116     {
    117         return *this>b||*this==b;
    118     }
    119     bign operator /(const bign &b) const
    120     {
    121         bign c,f=0;
    122         for(int i=len-1;i>=0;i--)
    123         {
    124             f=f*10;
    125             f.s[0]=s[i];
    126             while(f>=b)
    127             {
    128                 f=f-b;
    129                 c.s[i]++;
    130             }
    131         }
    132         c.len=len;
    133         c.clean();
    134         return c;
    135     }
    136 };
    137 istream &operator >>(istream &in,bign& x)  //重载输入
    138 {
    139     string s;
    140     in>>s;
    141     x=s.c_str();
    142     return in;
    143 }
    144 ostream & operator <<(ostream & out,const bign& x)  //重载输出
    145 {
    146     out<<x.str();
    147     return out;
    148 }
    149 int main()
    150 {
    151     bign a,b;
    152     cin>>a>>b;
    153     cout<<a/b;
    154     return 0;
    155 }
  • 相关阅读:
    Android SwipeActionAdapter结合Pinnedheaderlistview实现复杂列表的左右滑动操作
    Android 使用SwipeActionAdapter开源库实现简单列表的左右滑动操作
    你读到了什么:谈谈阅读的空与实
    飞行的架构师和奔跑的程序员
    poj 3252 数位dp
    hdu 4734 数位dp
    hdu 2089 不要62 数位dp入门
    蓝桥杯模拟赛 青出于蓝而胜于蓝
    bzoj 4034
    hdu 3974 dfs时间戳+线段树
  • 原文地址:https://www.cnblogs.com/aininot260/p/9305832.html
Copyright © 2020-2023  润新知