高精度算法解析和高精度赛场用模板

1.高精度算法介绍

    高精度算法,又称数值处理算法。意在通过数组模拟较大整数的存储和使用。本篇文章就会给大家介绍赛场上使用的精简版高精度算法模版。

2.高精度结构体前置函数

2.1.定义高精度结构体

    首先定义一个高精度结构体。用数组a储存这个数,用变量len储存这个数的长度。MAXN代表数组a的最大长度。

#define MAXN 1010
struct bigint
{
    int len,a[MAXN];
};

2.2.重载[ ]

    为了方便访问数组a中的元素,我们需要重载[ ]。

int &operator[](int i)//用x[i]代替x.a[i]
{
	return a[i];
}

2.2.构造函数

    我们有时会需要用低精度整数来初始化高精度整数。这个时候就需要构造函数了。注意:为了方便实用,数组a倒序存储这个数字,即a[1]代表这个数的最后一位,以此类推。

bigint(int x=0)//默认这个数是0
{
	memset(a,0,sizeof(a));//初始化数组a
	if(x==0)//如果x是0会直接跳过底下的循环,导致len被初始化为0,所以要特判
	{
		len=1;
		return;//直接返回
	}
	for(len=1;x;len++)//只要x没被取完就一直去并增加这个数的长度
	    a[len]=x%10,x/=10;//倒序存储x
	len--;//最后len总会多1
}

2.3.输入输出

    我们用一个字符串模拟输入。然后倒序存储。输出就直接倒序输出。

void in_data()//输入高精度整数
{
	string s;cin>>s;//暂时存储到字符串里面
	memset(a,0,sizeof(a));len=0;//清空数组并初始化这个大整数 
	for(int i=s.length()-1;i>=0;i--,len++)//字符串转整数
		a[s.length()-i]=s[i]-'0';
}

void print()//打印这个数字,注意数组a是倒着存储各个数位的
{
    //注意在后面的处理中可能会出现len=0的情况,所以i的初始值要写成max(num.len, 1)
	for(int i=max(len,1);i>=1;i--)
	    printf("%d",a[i]);//前面重载过[]了,等价于num.a[i]
}

2.4.展开

    在后面的处理中,我们不会直接处理进位,而是在最后使用flatten函数一口气处理。我们叫它“展开”。

void flatten(int L)//处理1到L范围内的进位并重置长度,需要保证L不小于有效长度
{
	len=L;//先赋一个初始值
	for(int i=1;i<=len;i++)//处理进位
		a[i+1]+=a[i]/10,a[i]%=10;
	while(!a[len])//将多余的长度去掉
		len--;
}

3.重载高精度加法

    回顾一下我们小学学的竖式加法。套用模拟问题的思路,我们就可以实现高精度加法。

//为了方便演示,这里定义成友元函数,暂时不需要知道为什么,也可以自己上网搜一下
friend bigint operator+(bigint a,bigint b)//重载高精度加法
{
	bigint c;//存储最终的答案
	int _len=max(a.len,b.len);//累加
	for(int i=1;i<=_len;i++)//循环累加
	    c[i]+=a[i]+b[i];
	c.flatten(_len+1);//计算后最多不超过_len+1位
	return c;
}

4.重载高精度乘法

    跟高精度加法一样,高精度乘法也是通过模拟乘法竖式实现的。但直接寻找规律有一些复杂。我们先不处理进位,将乘法数竖式列成表格的形式观察。

第6位第5位第4位第3位第2位第1位
a514
b495
a*b[1]25520
a*b[2]45936
a*b[3]20416
中间产物2049504120
处理进位2,进025,进254,进554,进543,进420,进2
结果254430

    通过观察可以发现,第一个数的第i位乘第二个数的第j位的值贡献给了答案的i+j-1位。因此,我们可以先计算贡献,最后处理进位。

    上表借鉴了深入浅出入门篇,请见谅

friend bigint operator*(bigint a,bigint b)//重载高精度乘法
{
	bigint c;//储存答案
	int lena=a.len,lenb=b.len;
	for(int i=1;i<=lena;i++)//遍历a的每一位
        for(int j=1;j<=lenb;j++)//遍历b的每一位
		    c[i+j-1]+=a[i]*b[j];//计算贡献
	c.flatten(lena+lenb);//答案长度不会超过两数长度之和
	return c;
}

5.完整代码

#define MAXN 1010
struct bigint
{
    int len,a[MAXN];
    bigint(int x=0)//默认这个数是0
    {
	    memset(a,0,sizeof(a));//初始化数组a
	    if(x==0)//如果x是0会直接跳过底下的循环,导致len被初始化为0,所以要特判
	    {
		    len=1;
		    return;//直接返回
	    }
	    for(len=1;x;len++)//只要x没被取完就一直去并增加这个数的长度
	        a[len]=x%10,x/=10;//倒序存储x
	    len--;//最后len总会多1
    }
    
    int &operator[](int i)//用x[i]代替x.a[i]
    {
	    return a[i];
    }
    
    void in_data()//输入高精度整数
    {
	    string s;cin>>s;//暂时存储到字符串里面
	    memset(a,0,sizeof(a));len=0;//清空数组并初始化这个大整数 
	    for(int i=s.length()-1;i>=0;i--,len++)//字符串转整数
		    a[s.length()-i]=s[i]-'0';
    }

    void print()//打印这个数字,注意数组a是倒着存储各个数位的
    {
        //注意在后面的处理中可能会出现len=0的情况,所以i的初始值要写成max(num.len, 1)
	    for(int i=max(len,1);i>=1;i--)
		    printf("%d",a[i]);//前面重载过[]了,等价于num.a[i]
    }
    
    void flatten(int L)//处理1到L范围内的进位并重置长度,需要保证L不小于有效长度
    {
	    len=L;//先赋一个初始值
	    for(int i=1;i<=len;i++)//处理进位
		    a[i+1]+=a[i]/10,a[i]%=10;
 	    while(!a[len])//将多余的长度去掉
		    len--;
    }

    friend bigint operator+(bigint a,bigint b)//重载高精度加法
    {
	    bigint c;//存储最终的答案
	    int _len=max(a.len,b.len);//累加
	    for(int i=1;i<=_len;i++)//循环累加
	        c[i]+=a[i]+b[i];
	    c.flatten(_len+1);//计算后最多不超过_len+1位
	    return c;
    }
    
    friend bigint operator*(bigint a,bigint b)//重载高精度乘法
    {
	    bigint c;//储存答案
	    int lena=a.len,lenb=b.len;
	    for(int i=1;i<=lena;i++)//遍历a的每一位
            for(int j=1;j<=lenb;j++)//遍历b的每一位
		        c[i+j-1]+=a[i]*b[j];//计算贡献
	    c.flatten(lena+lenb);//答案长度不会超过两数长度之和
	    return c;
    }
};
  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值