《算法笔记》读书记录DAY_12

本文介绍了大整数(高精度整数)的存储方式,通过数组存储并利用结构体记录长度。详细讲解了大整数的加法、减法操作,以及如何将大整数与低精度整数进行乘法和除法运算。在加法中,使用逐位相加和进位的概念;在减法中,处理了不够减的情况;乘法涉及逐位相乘与进位;除法则通过不断求余和比较来实现。此外,还讨论了负数的处理和结果的规范化。

CHAPTER_5  数学问题入门

5.6.1大整数的存储 

大整数又称高精度整数,其含义是用基本数据类型无法存储其精度的整数。 例如一个有1000个数位的整数,我们无法用基本数据类型来存储这个数。

我们使用一个数组来存储大整数。例如定义一个int型数组d[1000],将整数235813存入,即有d[0]=3,d[1]=1,d[2]=8,d[3]=5,d[4]=3,d[5]=2。即整数的高位存储在数组的高位,整数的地位存储在数组的低位。需要注意的是,把整数按字符串%s读入时需要反转再存入数组d[]。

大整数存储结构定义如下:

typedef struct {

        int d[1000];

        int len;                                      //d[]数组存放整数,len记录长度

        bign() {

                memset(d,0,sizeof(d));

                len=0;

        }                                               // 自定义构造函数,用于自动初始化结构体变量 

}bign;

我们在输入大整数时,首先用字符串读入,然后将其翻转存入bign结构体中

bign change(string str) {               //将输入字符串存入结构体中 
    bign a;
    a.len=str.length();                 //赋值整数的长度
    reverse(str.begin(),str.end());     //reverse()函数位于algorithm头文件,用于反转   
    for(int i=0;i<a.len;i++) {
        a.d[i]=str[i]-'0';
    }                                   //为d[]依次赋值 
    return a;
}  

解决了存储和输入问题后,我们怎么比较两个大整数的大小呢?

规则很简单:先判断两者的bign.len的大小,如果不相等,则len大的bign大;如果相等,遍历两者的d[1000]从高位到地位进行比较,直到出现某一位不等,就可以判断两者大小。

 5.6.2大整数的四则运算

我们主要介绍四种大整数运算:高精度加法、高精度减法、高精度乘低精度、高精度除以低精度。 至于高精度与高精度的乘除,一般考试不会涉及,故不在此赘述。

高精度加法

加法原理很简单 ,我们对某一位进行相加,得出的数字中,个位数作为该位结果,十位数作为下一位的进位。我们可以得到代码如下:

bign add(bign a,bign b) {
	bign c;
	int tmp=0;                              //临时变量,用来存储进位
	for(int i=0;i<a.len||i<b.len;i++) {
		int sum=a.d[i]+b.d[i]+tmp;
		c.d[i]=sum%10;                   //两个数的对应位相加,再加上进位,余10取出个位    
		c.len++;
		tmp=sum/10;                      //十位取出,赋予tmp 
	} 
	if(tmp) {                           //如果最后进位不为0,说明结果数比原来两个数位数更高 
		c.d[c.len]=tmp;                   //例如55+60=115,将多余的进位赋予c 
		c.len++;
	}
    return c;
}

高精度减法

减法的步骤也很容易,我们先假设被减数a大于减数b。对某一步,比较被减位和减位,如果不够减,则令高位减1被减位加10,再进行减法;如果够减,则直接减。

bign minu(bign a,bign b) {
	bign c;
	for(int i=0;i<a.len||i<b.len;i++) {
		if(a.d[i]<b.d[i]) {
			a.d[i+1]--;
			a.d[i]+=10;
		}                         //如果不够减,则向高位借位 
		c.d[i]=a.d[i]-b.d[i];
		c.len++;                  //将结果赋予c 
	}
	while(c.d[len-1]==0&&c.len!=1) {
		c.len--;
	}                             //去除高位的0,例如2233-2211=0022,将开头的两个0去除 
	return c;
}

 PS:在上面的讨论中我们已经解决了高精度之间的加减。但是还有两个小问题要注意。

(1)加法时如果两个数为负数,我们将负号去除,再按照上面算法做加法,最后结果再加负号。

(2)上面的减法过程中,默认减数大于被减数。我们将减数和被减数互换,按照上面算法做减法,最后结果再加负号。

高精度乘低精度

低精度就是可以用基本类型存储的数据,例如int型。乘法过程稍比加法复杂,我们以147*35为例。(假设147为bign类型,35为int型)

因此对于某一步:取bign的某位与int数相乘,再与进位相加,所得个位数为当位结果,高位部分作为进位。

bign multi(bign a,int n) {
	bign c;
	int tmp=0;                  //tmp存储进位 
	for(int i=0;i<a.len;i++) {
		int sum=a.d[i]*n+tmp;
		c.d[i]=sum%10;
		c.len++;
		tmp=sum/10;
	}
	while(tmp) {            //与加法不同,乘法进位可能不止一位数,因此要循环处理 
		c.d[c.len-1]=tmp%10;
		c.len++;
		tmp/=10;
	}
	return c;
} 

高精度除以低精度 

我们以1234/7为例。(假设1234为bign类型,7为int型)

因此对于某一步:上一步的余数乘以10加上该步的位,得到该步临时的被除数,将其与除数比较:如果不够除,则该位商为0;如果够除,则商为对应的商,余数即为对应的余数。

bign divide(bign a,int b,int& r) {    //r为余数 
	bign c;
	c.len=a.len;                      //被除数的每一位和商的每一位是一一对应的,因此先令长度相等
	for(int i=a.len-1;i>=0;i--) {
		r=r*10+a.d[i];                //和上一位的余数组合成被除数
		if(r<b)
			c.d[i]=0;
		else {
			c.d[i]=r/b;
			r=r%b;
		} 
	} 
	while(c.d[len-1]==0&&c.len!=1) {  //和减法相同,去除高位0 
		c.len--; 
	}
	return c;
} 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值