高精度运算(除法待完善)

Posted 东条希尔薇

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了高精度运算(除法待完善)相关的知识,希望对你有一定的参考价值。

我们知道,在c语言中,数据的存储是有范围的,超出了这个范围的数据将不能有效的进行存储和运算

而超出c语言储存范围的数,不能用c语言基本数据类型储存的数据,就叫做大数

所以,为了解决大数的运算问题,我们来介绍一下如何在c语言中实现大数运算

大数加减法

首先介绍最基本的大数加减法

这篇文章中我们把任意小于200位的非负整数的数都称作大数

例如:88888888888888888888,123456789987654321

而我们要储存这么大的数字,只能用一个字符数组来储存

char a[200]=0;
char b[200]=0;

例如,我们要存储123456789这个数字,在内存中只能这么储存

但我们在两个数字进行运算的时候,当遇到进位的时候,需要将所有数字往后移动一位,为了避免这种麻烦,也为了能方便控制下标

所以我们在运算中需要将数字倒过来存储,并将其存储至另外一个整数数组中

int a1[200]=0;
int b1[200]=0;

存储方式如下

	int len_a = strlen(a);
	int len_b = strlen(b);//先求出两个数字的位数
	int i = 0;
	for (i = 0; i < len_a; i++)
	
		a1[len_a - 1 - i] = a[i] - '0';
	

	for (i = 0; i < len_b; i++)
	
		b1[len_b - 1 - i] = b[i] - '0';
	//为运算做准备

接下来就要进行运算了,运算结果为了表示方便,运算结果同样存储在一个整型数组中保存

运算就可以一位一位的进行运算,但也需要先确定和运算的位数

int len = len_a > len_b ? len_a : len_b;//求和用的长度
sum[i] = a1[i] + b1[i]

但是加法,我们必须要考虑进位的情况

我们在运算中有一些位数运算结果已经大于10了,代表需要进行进位

我们可以用一个临时变量d保存我们的进位信息

某一位数大于10,就代表我们需要进位了

  • 用/提取第一位数字,也就是进位数

  • 用%提取最后位数字,也就是此位数

提取到的进位数,就需要加在下一次位数运算中,就这样算一位就马上将进位数保存,加在下一次运算中

也就像这样

sum[i] = a1[i] + b1[i] + d;

但还有一种情况,在最高位进位的情况

只需要在运算完成后,检查进位数是否为0,若不为0,则进位并把结果总位数加一

完整代码实现

int main()

	char a[200] =  0 ;
	char b[200] =  0 ;//保存求和的两个大数
	int a1[200] =  0 ;
	int b1[200] =  0 ;//进行运算的临时数组
	int sum[201] =  0 ;//存放和的数组,由于进位需要多一位
	char out_sum[201] =  0 ;//需要表示大数和的字符串
	scanf("%s", a);
	scanf("%s", b);//读入两个大数
	int len_a = strlen(a);
	int len_b = strlen(b);
	int i = 0;
	for (i = 0; i < len_a; i++)
	
		a1[len_a - 1 - i] = a[i] - '0';
	

	for (i = 0; i < len_b; i++)
	
		b1[len_b - 1 - i] = b[i] - '0';
	//为运算做准备
	
	int len = len_a > len_b ? len_a : len_b;//求和用的长度

	int d = 0;//保存进位结果
	for (i = 0; i < len; i++)
	
		sum[i] = a1[i] + b1[i] + d;
		if (sum[i] > 10)
		
			d = sum[i] / 10;//算进位
			sum[i] %= 10;//算余数

		
		else
			d = 0;//没有进位则需要将进位重置

	

	if (d > 0)
	
		sum[len] += d;
		len++;
	//最高位需要进位的情况
	
	for (i = 0; i < len; i++)
	
		out_sum[i] = sum[len -1 - i] + '0';
	
	
	for (i = 0; i < len; i++)
	
		printf("%c", out_sum[i]);
	
	return 0;

测试用例

大数乘法

这里的大数指的是小于50位的非负整数

其存储方式的思想和大数加法的思想差不多

主要讲一下大数乘法的运算

类比于手算,我们也需要一位一位的进行运算,同样先不考虑进位,待所有位运算完成后统一进行

通过对乘法的理解我们发现:

i位和j位的运算结果放在i+j位中

for (i = 0; i < len_a; i++)
	
		
		for (j = 0; j < len_b; j++)
		
			pow[i + j] += a1[i] * b1[j];
		
	

而进位,则在最后进行,方法可以参考大数加法

int count = i + j - 1;//找到结果的最大位

	int d = 0;
	for (i = 0; i < count; i++)
	
		pow[i] += d;
		if (pow[i] > 10)
		
			d = pow[i] / 10;
			pow[i] %= 10;
		
		else
		
			d = 0;
		
	
	if (d > 0)
	
		pow[count] += d;
		count++;
	

完整代码实现

int main()

	char a[50] =  0 ;
	char b[50] =  0 ;
	int a1[50] =  0 ;
	int b1[50] =  0 ;
	int pow[100] =  0 ;
	char out_pow[100] =  0 ;
	scanf("%s", a);
	scanf("%s", b);
	int i = 0;
	int len_a = strlen(a);
	int len_b = strlen(b);

	
	for (i = 0; i < len_a; i++)
	
		a1[len_a - 1 - i] = a[i] - '0';
	

	for (i = 0; i < len_b; i++)
	
		b1[len_b - 1 - i] = b[i] - '0';
	
	int j = 0;
	for (i = 0; i < len_a; i++)
	
		
		for (j = 0; j < len_b; j++)
		
			pow[i + j] += a1[i] * b1[j];
		
	

	int count = i + j - 1;

	int d = 0;
	for (i = 0; i < count; i++)
	
		pow[i] += d;
		if (pow[i] > 10)
		
			d = pow[i] / 10;
			pow[i] %= 10;
		
		else
		
			d = 0;
		
	
	if (d > 0)
	
		pow[count] += d;
		count++;
	

	for (i = 0; i < count; i++)
	
		out_pow[i] = pow[count -1 - i] + '0';
	
	
	for (i = 0; i < count; i++)
	
		printf("%c", out_pow[i]);
	
	return 0;

测试:

大数除法

这里的大数指的是小于100位的非负整数

并且,除法运算做的是int类型的运算,也就是运算结果中没有小数点

前面的大数加法,乘法都是模拟的手工运算

但大数除法直接手算模拟却非常麻烦,因为除法不能一位一位的进行运算

所以我们必须要模拟大数减法进行实现

基本思想:反复做减法,看看被除数能减除数多少次

例如7546除以23中,7546能被23减去328次,所以最后结果是328

但这么一次次的减,效率显然比较低,为了提高程序的效率,我们可以先将除数位数升高到与被除数相同,再进行减法运算,可大大减少运算次数

  • 上面的算式中,先把23提升到2300,7546能被2300减去3次,所以商的值增加300

  • 减完后剩下646,先把23提升到230,646能被230减去2次,所以商的值增加20

以此类推。。。

但这个代码中,需要先实现一个大数减法的功能,再进行运算

int Subtract(int* a1, int* b1, int len_a, int len_b, int* sub)

	int i = 0;
	if (len_a < len_b)
		return -1;
	else if (len_a == len_b)
	
		for (i = len_a - 1; i >= 0; i++)
		
			if (a1[i] < b1[i])
				return -1;
		
	//首先判断被减数是否比减数大
	int d = 0;
	for (i = 0; i < len_a; i++)
	
		sub[i] = a1[i] - b1[i] + d;
		if (sub[i] < 0)
		
			sub[i] += 10;
			d = -1;
		
		else
		
			d = 0;
		//涉及到了借位
	
	for (i = len_a - 1; i >= 0; i++)
	
		if (sub[i])
			return i + 1;//返回结果的位数
	
	return 0;

以上是关于高精度运算(除法待完善)的主要内容,如果未能解决你的问题,请参考以下文章

小学二年级四则运算题

请问怎样用加法-移位实现定点乘除法?

计算机原理 3.6 定点数除法

高精度运算 加法减法

补四则运算

数字集成电路设计---除法运算