大整数的四则运算

对一道 A+B 的题目, 如果A 和 B的范围在 int 范围内, 那么将非常简单。但是如果A 和 B是有着1000个数位的整数,就不能简单地用已有的数据类型来表示, 必然会发生溢出。此外, 大整数又称为高精度整数, 其含义就是用基本数据类型无法存储其精度的整数。

大整数的存储:

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

struct bignum{
	int d[1000];
	int len;
	bignum(){		//该为构造函数 
		memset(d, 0, sizeof(d));
		len = 0;
	}
};

“构造函数”是用来初始化结构体的函数, 函数名和结构体相同, 无返回值。在定义结构体变量之后,它会马上初始化结构体。

memset函数是用来初始化数组,头文件为 string.h 

转换:

bignum change(char str[]){
	bignum a;
	
	a.len = strlen(str);
	
	for(int i = 0; i < a.len; i++){
		a.d[i] = str[a.len - i - 1] - '0';		//逆着赋值 
	}
	
	return a;
}

比较:

int compare(bignum a, bignum b){
	if(a.len > b.len){		// 先比较两个数的位数, 位数长的数更大 
		return 1;
	}else if(a.len < b.len){
		return -1;
	}else{						// 再从高位往低位比较 
		for(int i=a.len - 1; i >= 0; i--){
			if(a.d[i] > b.d[i])	return 1;	// 	a > b
			else if(a.d[i] < b.d[i]) return -1;	//	a < b 
		}
		return 0;	//a = b
	}
}

高精度加法:

将该位上的两个数字相加,再与上一位的进位相加,得到的结果取个位数作为该位结果,取十位数作为新的进位。

bignum add(bignum a, bignum b){
	
	bignum c;
	int carry = 0;
	
	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){
		c.d[c.len++] = carry;
	}
	
	return c;
}

高精度减法:

对某一步,比较被减位与减位, 如果不够减,则令被减位的高位减 1, 被减位加 10再进行减法; 如果够减, 则直接减。最后一步要注意减法后高位可能有多余的 0, 要去除它们, 但也要保证结果至少有一位书

bignum sub(bignum a, bignum b){
	
	bignum 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;
}

最后需要注意,使用 sub 函数前要比较两个数的大小, 如果被减数小于减数, 则需要交换两个变量, 然后输出负号,再使用sub函数。

高精度与低精度的乘法

所谓的低精度就是可以用基本数据类型存储的数据, 例如 int 型。这里讲述的就是 bignum 类型 与 int 类型的乘法。

对某一步来说就是这么一个步骤:取 bignum 的某位与 int 型整体相乘, 再与进位相加, 所得结果的个位数作为该位结果,高位部分作为新的进位。

bignum multi(bignum a, int b){
	bignum 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){			//和加法不一样,乘法的进位可能不止一位 
		c.d[c.len++] = carry % 10;
		carry /= 10;
	}
	
	return c;	
}

另外,如果 a 和 b 存在负数, 需要先记录下其负号,然后取它们的绝对值带入函数

高精度与低精度的除法

上一步的余数乘以 10 加上该步的位, 得到该步临时的被除数, 将其与除数比较:如果不够除,则该位的商为 0; 如果够除,则商即为对应的商, 余数即为对应的余数。最后一步要注意减法后高位可能有多余的 0,要去除它们, 但也要保证结果至少有一位数。

bignum divide(bignum a, int b, int& r){		// r 为余数 
	
	bignum c;
	c.len = a.len;	//被除数的每一位数和商的每一位是一一对应的,因此先令长度相等 
	for(int i = a.len - 1; i >= 0; i--){	//从高位开始 
		r = r * 10 + a.d[i];	//和上一位遗留的余数组合 
		if(r < b){			// 不够除,该位为 0 
			c.d[i] = 0;
		}else{				//够除 
			c.d[i] = r / b;		//商 
			r = r % b;			//获得新的余数 
		}
	}
	while(c.len - 1 >= 1 && c.d[c.len - 1] == 0){
		c.len--;     //去除高位的 0,同时至少保留一位最低为 0 
	}
	
	return c;
} 

 

其完整代码如下:

#include <cstdio>
#include <cstring> 
struct bignum{
	int d[1000];
	int len;
	bignum(){		//该为构造函数 
		memset(d, 0, sizeof(d));
		len = 0;
	}
};
bignum change(char str[]){
	bignum a;
	 
	a.len = strlen(str);
	
	for(int i = 0; i < a.len; i++){
		a.d[i] = str[a.len - i - 1] - '0';		//逆着赋值 
	}
	
	return a;
}
int compare(bignum a, bignum b){
	if(a.len > b.len){		// 先比较两个数的位数, 位数长的数更大 
		return 1;
	}else if(a.len < b.len){
		return -1;
	}else{						// 再从高位往低位比较 
		for(int i=a.len - 1; i >= 0; i--){
			if(a.d[i] > b.d[i])	return 1;	// 	a > b
			else if(a.d[i] < b.d[i]) return -1;	//	a < b 
		}
		return 0;	//a = b
	}
}
bignum add(bignum a, bignum b){
	
	bignum c;
	int carry = 0;
	
	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){
		c.d[c.len++] = carry;
	}
	
	return c;
}
bignum sub(bignum a, bignum b){
	
	bignum 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,同时至少保留一位最低为 0 
	}
	
	return c;
}
bignum multi(bignum a, int b){
	bignum 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){			//和加法不一样,乘法的进位可能不止一位 
		c.d[c.len++] = carry % 10;
		carry /= 10;
	}
	
	return c;	
}
bignum divide(bignum a, int b, int& r){		// r 为余数 
	
	bignum c;
	c.len = a.len;	//被除数的每一位数和商的每一位是一一对应的,因此先令长度相等 
	for(int i = a.len - 1; i >= 0; i--){	//从高位开始 
		r = r * 10 + a.d[i];	//和上一位遗留的余数组合 
		if(r < b){			// 不够除,该位为 0 
			c.d[i] = 0;
		}else{				//够除 
			c.d[i] = r / b;		//商 
			r = r % b;			//获得新的余数 
		}
	}
	while(c.len - 1 >= 1 && c.d[c.len - 1] == 0){
		c.len--;     //去除高位的 0,同时至少保留一位最低为 0 
	}
	
	return c;
} 
void Print(bignum a){
	for(int i= a.len - 1; i >= 0; i--)
		printf("%d", a.d[i]);
	printf("\n");
}
int main(){
	
	char str1[1000], str2[1000];
	
	scanf("%s%s", str1, str2);
	
	bignum a = change(str1);
	bignum b = change(str2);
	
	//高精度加法  
	printf("a + b = "); 
	Print(add(a, b));
	
	//高精度减法 
	printf("a - b = ");
	if(compare(a, b) == -1){
		printf("-1");
		Print(sub(b, a)); 			
	}else{
		Print(sub(a, b));
	}
		 
	//高精度与低精度的乘法
	int b1 = 0;
	for(int i=0; i < strlen(str2); i++){	//将字符串代表的数字转换为 int 类型 
		b1 = b1 * 10 + (str2[i] - '0');
	}
	printf("a * b = ");	
	Print(multi(a, b1)); 
	
	//高精度与低精度的除法
	int r = 0;  //余数 r , 即 a % b = r 
	printf("a / b = ");	
	Print(divide(a, b1, r)); 
	printf("a % b = %d\n", r); 
	
	return 0;
}

 

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值