zoukankan      html  css  js  c++  java
  • 高精度——压位的思想及应用

    本文作者frankchenfu,blogs网址http://www.cnblogs.com/frankchenfu/,转载请保留此文字。
    这里我们简单介绍一下高精度的计算。
    我们都知道在Cpp/C/Pas等语言中,整数最大能储存(2^{64} -1),超过这个范围就表示不了了(不包括个别支持int128的编译器)。这个时候,我们如果希望把这些整数存储下来,就需要用到高精度的算法和思想。高精度就是像小学学过的竖式运算一样的(除法除外)。然后就直接模拟即可。除法一位一位地试商即可。
    接下来我们发现就是一位一位地加减很慢,我们考虑如何把它加快速度(减小常数)。如果你有学习过关于bitset的相关知识,那你肯定对压位的方法不陌生。我们把十进制位中的每4~8位并在一起(笔者一般压4位,因为乘法时不会超过int的范围),然后照样加减,最后并不影响答案,但是要注意输出。对于除法,我们此时发现枚举(10^4)(10^8)太慢了,注意到单调性,于是我们考虑二分试商,这样就也可以在(log_2 BASE)的时间之内求出来了。
    注意初始化、赋值和输出。

    #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;
    }
    
  • 相关阅读:
    .NET:CLR via C# A Brief Look at Metadata
    在容器中运行 Jenkins pipeline 任务
    Azure AI 服务之文本翻译
    linux journalctl 命令
    容器化的 DevOps 工作流
    System V IPC 之消息队列
    System V IPC 之信号量
    System V IPC 之共享内存
    减小容器镜像的三板斧
    linux chroot 命令
  • 原文地址:https://www.cnblogs.com/frankchenfu/p/8158941.html
Copyright © 2011-2022 走看看