大整数及其四则运算

【大整数的存储】

  • 例如将整数 235813 存储到数组中,则有 d[0] = 3, d[1] = 1, d[2] = 8, d[3] = 5, d[4] = 3, d[5] = 2,即整数的高位存储在数组的高位,整数的低位存储在数组的低位。不反过来存储的原因是,在进行运算的时候都是从整数的低位到高位进行枚举,顺位存储和这种思维相合。

  • 但是也会由此产生一个需要注意的问题:把整数按字符串 %s 读入的时候,实际上是逆位存储的,即 str[0] = 2’, str[1] = ‘3’, …, str[5] = ‘3’,因此在读入之后需要在另存为至 d[] 数组的时候反转一下。

  • 而为了方便随时获取大整数的长度,一般都会定义一个 int 型变量 len 来记录其长度,并和 d 数组组合成结构体:

struct bign
{
	int d[1000];
	int len;
	bign()
	{
		memset(d, 0, sizeof(d));
		len = 0;
	}
};
  • 这里 bign 是 big number 的缩写。

  • 显然,在定义结构体变量之后,需要马上初始化结构体。为了减少在实际输入代码时总是忘记初始化的问题,最好使用“构造函数” 来初始化结构体的函数,其函数名和结构体名相同、无返回值,这样在每次定义结构体变量时,都会自动对该变量进行初始化。

  • 而输入大整数时,一般都是先用字符串读入,然后再把字符串另存为至 bign 结构体。由于使用 char数组进行读入时,整数的高位会变成数组的低位,而整数的低位会变成数组的高位,因此为了让整数在 bign 中是顺位存储,需要让字符串倒着赋给 d[] 数组:

bign change(char str[])	//将整数转换为bign 
{
	bign a;
	a.len = strlen(str);	//bign的长度就是字符串的长度
	for(int i=0;i<a.len;i++)
		a.d[i] = str[a.len-i-1] - '0';//逆着赋值 
	
	return a;
}

【大整数的比较】

  • 如果要比较两个 bign 变量的大小,规则也很简单:先判断两者的 len 大小,如果不相等,则以长的为大;如果相等,则从高位到低位进行比较,直到出现某一位不等,就可以判断两个数的大小。

下面的代码直接依照了这个规则:

int compare(bign a, bign b)//比较a和b大小,a大、相等、a小分别返回1、0、-1 
{
	if(a.len>b.len)
		return 1;//a大 
	else if(a.len<b.len)
		return -1;//a小
	else
	{
		for(int i=a.len-1;i>=0;i--)	//从高位往低位比较 
		{
			if(a.d[i]>b.d[i])	//只要有一位a大,则a大 
				return 1;
			else if(a.d[i]<b.d[i])	//只要有一位a小,则a小 
				return -1;
		}
		
		return 0;	//两数相等 
	} 
}

【高精度加法】

在这里插入图片描述

bign add(bign a, bign b)	//高精度a+b 
{
	bign c;
	int carry = 0; //carry是进位
	for(int i=0;i<a.len||i<b.len;i++)	//以较长的为界限 
	{
		int temp = a.d[i] + b.d[i] + carry; //两个对应位与进位相加
		c.d[c.len++] = temp%10;	//个位数为该位结果
		carry = temp/10; //十位数为新的进位 
	}
	
	if(carry!=0)	//如果最后进位不为0,则直接赋给结果的最高位 
		c.d[c.len++] = carry;
	
	return c; 
} 
//用法样例
void print(bign a)
{
	for(int i=a.len-1;i>=0;i--)
		printf("%d",a.d[i]);
}

int main()
{
	char str1[1000],str2[1000];
	scanf("%s%s",str1,str2);
	bign a = change(str1);
	bign b = change(str2);
	print(add(a,b));
	return 0;
}

  • 最后指出,这样写法的条件是两个对象都是非负整数。如果有一方是负的,可以在转换到数组这步时去掉其负号,然后采用高精度减法;如果两个都是负的,就都去掉负号后用高精度加法,最后再把负号加回去即可。

【高精度减法】

在这里插入图片描述

bign sub(bign a, bign b)	//高精度a-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;  //当前位加10 
		}
		c.d[c.len++] = a.d[i] - b.d[i];	//减法结果为当前位结果
	}
	
	while(c.len-1>=1&&c.d[c.len-1]==0)
		c.len--;	//去除高位的0,同时至少保留一位最低位 
	
	return c; 
}

【高精度乘低精度】

在这里插入图片描述

bign multi(bign a, bign b)	//高精度乘低精度 
{
	bign c;
	int carry = 0;//进位 
	for(int i=0;i<a.len;i++)	//以较长的为界限 
	{
		int temp = a.d[i]*b+carry;
		c.d[c.len++] = temp%10;   //个位作为该位结果 
		carry = temp/10;   //高位部分作为新的进位
	}
	
	while(carry!=0) 	//和加法不一样,乘法进位可能不止一位,因此用while 
	{
		c.d[c.len++] = carry%10;
		carry /= 10;
	 } 
	
	return c; 
}
  • 如果a和b中存在负数,需记录下其负号,然后取它们的绝对值代入函数

【高精度除低精度】

在这里插入图片描述

bign divide(bign a, bign 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;  //不够除,该位为0
		else
		{
			c.d[i] = r/b;  //商
			r = r%b;  //获得新的余数 
		} 
	}
	
	while(c.len-1>=1&&c.d[c.len-1]==0)
		c.len--;		//去除高位的0,同时至少保留一位最低位
	
	return c; 
}

猜你喜欢

转载自blog.csdn.net/qq_42815188/article/details/88932567
今日推荐