C语言超大数字的储存以及运算

前言

众所周知,C语言的数据类型有好几种,而其都有大小限制,比如说常见的长整型,其占用内存4个字节,可以储存的数字的大小为-2147483648~2147483647,但是在编程的时候,我们有可能会碰到非常非常大的数字,其可能超过长整型的最大上线导致数据溢出,所以我们得想一个方法来让C语言能够储存并且·处理超大数字。

我这篇博客文章便提供了一个思路,将超大的数字作为数组来进行处理,并自行编写各个数组之间的加减乘除之间的运算

加法处理

首先是加法,小学也是先讲解加法的,我们这篇主要用来讨论正整数的大数字之间的运算,如果是有小数或者负数请修改相应的代码即可。

加法的思路,就按照我们一般手工计算的思路,

首先从最末尾进行运算,大于十的进一位便可以了

代码如下,代码中的数组a和b便是要相加的两个大数字,数组c即为计算的结果,可以根据需要将代码定义为函数。


//C语言数字超过上限的解决方案(通过数组来处理)
#include<stdio.h>


int main()
{	
	int a[20] = {0,0,0,0,0,1,2,3,4,5,6,7,8,9,2,3,1,4,2,2};        //第一个数字
	for (int i=0;i<=19;i++)										//输出一下
	{
		printf("%d", a[i]);
	}
	printf("\n");
	int b[20] = { 0,0,0,0,3,5,3,1,5,9,7,5,6,7,8,4,2,4,8,1 };		//第二个数字
	for (int i = 0; i <= 19; i++)									//输出一下
	{
		printf("%d", b[i]);
	}
	printf("\n");
	int c[20] = {0};												//定义结果的数组
	int temp = 0;										//进位符
	for (int i = 0; i <= 19; i++)
	{
		if (temp == 0)									//判断是否要进位
		{
			if (a[19 - i] + b[19 - i] < 10)
			{
				c[19 - i] = a[19 - i] + b[19 - i];
			}
			else
			{
				c[19 - i] = a[19 - i] + b[19 - i] - 10;
				temp = 1;
			}
		}
		else
		{
			if (a[19 - i] + b[19 - i] + 1 < 10)
			{
				c[19 - i] = a[19 - i] + b[19 - i] + 1;
				temp = 0;
			}
			else
			{
				c[19 - i] = a[19 - i] + b[19 - i] + 1 - 10;
				temp = 1;
			}
		}
	}
	for (int i = 0; i <= 19; i++)						//输出结果
	{
		printf("%d", c[i]);
	}
	printf("\n");
	return 0;

}

减法

解决完加法,那么肯定要来解决减法,加法跟减法类似,只不过是退位而不是进位,但是下方给的代码是无法处理负数的,具体处理负数的情况请对源代码进行稍加修改,这里的代码只是用来提供思路的。

//C语言数字超过上限的解决方案(通过数组来处理)(a-b)
#include<stdio.h>


int main()
{	
	int a[20] = {0,0,0,0,7,1,2,3,4,5,6,7,8,9,2,3,1,4,2,2};        //第一个数字
	for (int i=0;i<=19;i++)										//输出一下
	{
		printf("%d", a[i]);
	}
	printf("\n");
	int b[20] = { 0,0,0,0,3,5,3,1,5,9,7,5,6,7,8,4,2,4,8,1 };		//第二个数字
	for (int i = 0; i <= 19; i++)									//输出一下
	{
		printf("%d", b[i]);
	}
	printf("\n");
	int c[20] = {0};												//定义结果的数组
	int temp = 0;										//进位符
	for (int i = 0; i <= 19; i++)
	{
		if (temp == 0)									//判断是否要退位
		{
			if (a[19 - i] - b[19 - i] >= 0)
			{
				c[19 - i] = a[19 - i] - b[19 - i];
			}
			else
			{
				c[19 - i] = a[19 - i] - b[19 - i] + 10;
				temp = 1;
			}
		}
		else
		{
			if (a[19 - i] - b[19 - i] - 1 >= 0)
			{
				c[19 - i] = a[19 - i] - b[19 - i] - 1;
				temp = 0;
			}
			else
			{
				c[19 - i] = a[19 - i] - b[19 - i] - 1 + 10;
				temp = 1;
			}
		}
	}
	for (int i = 0; i <= 19; i++)						//输出结果
	{
		printf("%d", c[i]);
	}
	printf("\n");
	return 0;

}

乘法

乘法就比较复杂了,也是按照我们人手工计算的方法

代码实现思路:被乘数先乘以乘数的最后一位,然后被乘数再乘以乘数的倒数第二位然后乘以一个十,一次类推,将刚刚上述的式子计算结果加在一起,输出结果即可

编写代码的时候要注意数据的大小,可能两个数子相乘会出现大于我们使用的数组的大小的情况,代码中要做好异常处理

//C语言数字超过上限的解决方案(通过数组来处理)
#include<stdio.h>


int main()
{
	int a[20] = {0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8};        //第一个数字
	for (int i=0;i<=19;i++)										//输出一下
	{
		printf("%d", a[i]);
	}
	printf("\n");
	int b[20] = { 0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8 };		//第二个数字
	for (int i = 0; i <= 19; i++)									//输出一下
	{
		printf("%d", b[i]);
	}
	printf("\n");
	int c[20] = {0};												//定义结果的数组

	int temp[20] = { 0 };
	int q = 0; //要进位的数字
	for (int i = 0; i <= 19; i++)
	{
		for (int x = 0; x <= 19; x++)
		{
			if (q == 0)
			{
				if (a[19 - x] * b[19-i] < 10)
				{
					temp[19 - x] = a[19 - x] * b[19 - i];
				}
				else
				{
					temp[19 - x] = (a[19 - x] * b[19 - i]) % 10;
					q = (a[19 - x] * b[19 - i] - (a[19 - x] * b[19 - i]) % 10) / 10;
				}
			}
			else
			{
				if (a[19 - x] * b[19 - i] + q < 10)
				{
					temp[19 - x] = a[19 - x] * b[19 - i] + q;
					q = 0;
				}
				else
				{
					temp[19 - x] = ((a[19 - x] * b[19 - i]) + q) % 10;
					q = ((a[19 - x] * b[19 - i] + q) - ((a[19 - x] * b[19 - i] + q) % 10)) / 10;
				}
			}
		}
		//先将结果后加零(小心溢出哦)(0的数量第一个加0个零,第二个加1个依次类推)
		//先判断下是否会溢出
		int Conter = 0;
		while (temp[Conter] == 0)
		{
			Conter = Conter + 1;
		}
		if (Conter == 20) continue;    //全零直接跳过
		if (i > Conter)
		{
			printf("抱歉超过最大计算上限,最大结果输出为20位,请修改程序源代码来支持更多的位数\n");
			return -1;
		}
		//然后往临时变量后面加零
		Conter = i;
		for (;Conter >0; Conter --)    
		{
			for (int Bubble_time = 0;Bubble_time < 19;  Bubble_time ++)
			{
				temp[Bubble_time] = temp[Bubble_time + 1];
			}
			temp[19] = 0;
		}
		//接下来将这些变量加在一起
		//这里直接用加法的代码,但是注意下记得修改变量名避免出错
		int ADD_temp = 0;										//进位符
		for (int ADD_i = 0; ADD_i <= 19; ADD_i++)
		{	
			if (ADD_temp == 0)									//判断是否要进位
			{
				if (c[19 - ADD_i] + temp[19 - ADD_i] < 10)
				{
					c[19 - ADD_i] = c[19 - ADD_i] + temp[19 - ADD_i];
				}
				else
				{
					c[19 - ADD_i] = c[19 - ADD_i] + temp[19 - ADD_i] - 10;
					ADD_temp = 1;
				}
			}
			else
			{
				if (c[19 - ADD_i] + temp[19 - ADD_i] + 1 < 10)
				{
					c[19 - ADD_i] = c[19 - ADD_i] + temp[19 - ADD_i] + 1;
					ADD_temp = 0;
				}
				else
				{
					c[19 - ADD_i] = c[19 - ADD_i] + temp[19 - ADD_i] + 1 - 10;
					ADD_temp = 1;
				}
			}
		}

		
	}
	for (int q = 0; q <= 19; q++)						//输出结果
	{
		printf("%d", c[q]);
	}
}

除法

除法便是最复杂的了,首先仍然看手工计算的草稿

按照手工计算的思路,便可以写出下方的代码

由于其中涉及了加减乘除,所以说已经将加减乘除的过程分辨定义为了函数,这样简化了代码,也方便了调用,调用函数返回的是一个数组指针,如同加法那里的代码一样,a为被除数,b为除数。

还有一点要注意的,假如这个除法的结果除不尽的话,函数会如同正常c除法一样返回取整的数字,下方代码并未提供取余数的函数,您可以自己添加

#include<stdio.h>
//加法的函数,返回数组指针
int *add(int a[20],int b[20])
{		
		static int c[20] = { 0 };
		for (int i = 0; i <= 19; i++)
		{
			c[i] = 0;
		}//定义结果的数组
		int temp = 0;										//进位符
		for (int i = 0; i <= 19; i++)
		{
			if (temp == 0)									//判断是否要进位
			{
				if (a[19 - i] + b[19 - i] < 10)
				{
					c[19 - i] = a[19 - i] + b[19 - i];
				}
				else
				{
					c[19 - i] = a[19 - i] + b[19 - i] - 10;
					temp = 1;
				}
			}
			else
			{
				if (a[19 - i] + b[19 - i] + 1 < 10)
				{
					c[19 - i] = a[19 - i] + b[19 - i] + 1;
					temp = 0;
				}
				else
				{
					c[19 - i] = a[19 - i] + b[19 - i] + 1 - 10;
					temp = 1;
				}
			}
		}
		return c;

}

//减法的函数,返回数组指针(a-b)
int* sub(int a[20], int b[20])
{	
	static int c[20] = { 0 };												//定义结果的数组
	for (int i = 0; i <= 19; i++)
	{
		c[i] = 0;
	}
	int temp = 0;										//进位符
	for (int i = 0; i <= 19; i++)
	{
		if (temp == 0)									//判断是否要退位
		{
			if (a[19 - i] - b[19 - i] >= 0)
			{
				c[19 - i] = a[19 - i] - b[19 - i];
			}
			else
			{
				c[19 - i] = a[19 - i] - b[19 - i] + 10;
				temp = 1;
			}
		}
		else
		{
			if (a[19 - i] - b[19 - i] - 1 >= 0)
			{
				c[19 - i] = a[19 - i] - b[19 - i] - 1;
				temp = 0;
			}
			else
			{
				c[19 - i] = a[19 - i] - b[19 - i] - 1 + 10;
				temp = 1;
			}
		}
	}
	return c;
}

// 乘法的函数,返回数组指针,返回NUll即为超出上限
int* rid(int a[20], int b[20])
{

	static int c[20] = { 0 };												//定义结果的数组
	for (int i = 0; i <= 19; i++)
	{
		c[i] = 0;
	}
	int temp[20] = { 0 };
	int q = 0; //要进位的数字
	for (int i = 0; i <= 19; i++)
	{
		for (int x = 0; x <= 19; x++)
		{
			if (q == 0)
			{
				if (a[19 - x] * b[19 - i] < 10)
				{
					temp[19 - x] = a[19 - x] * b[19 - i];
				}
				else
				{
					temp[19 - x] = (a[19 - x] * b[19 - i]) % 10;
					q = (a[19 - x] * b[19 - i] - (a[19 - x] * b[19 - i]) % 10) / 10;
				}
			}
			else
			{
				if (a[19 - x] * b[19 - i] + q < 10)
				{
					temp[19 - x] = a[19 - x] * b[19 - i] + q;
					q = 0;
				}
				else
				{
					temp[19 - x] = ((a[19 - x] * b[19 - i]) + q) % 10;
					q = ((a[19 - x] * b[19 - i] + q) - ((a[19 - x] * b[19 - i] + q) % 10)) / 10;
				}
			}
		}
		//先将结果后加零(小心溢出哦)(0的数量第一个加0个零,第二个加1个依次类推)
		//先判断下是否会溢出
		int Conter = 0;
		while (temp[Conter] == 0)
		{
			Conter = Conter + 1;
		}
		if (Conter == 20) continue;    //全零直接跳过
		if (i > Conter)
		{
			printf("抱歉超过最大计算上限,最大结果输出为20位,请修改程序源代码来支持更多的位数\n");
			return NULL;
		}
		//然后往临时变量后面加零
		Conter = i;
		for (; Conter > 0; Conter--)
		{
			for (int Bubble_time = 0; Bubble_time < 19; Bubble_time++)
			{
				temp[Bubble_time] = temp[Bubble_time + 1];
			}
			temp[19] = 0;
		}
		//接下来将这些变量加在一起
		//这里直接用加法的代码,但是注意下记得修改变量名避免出错
		int ADD_temp = 0;										//进位符
		for (int ADD_i = 0; ADD_i <= 19; ADD_i++)
		{
			if (ADD_temp == 0)									//判断是否要进位
			{
				if (c[19 - ADD_i] + temp[19 - ADD_i] < 10)
				{
					c[19 - ADD_i] = c[19 - ADD_i] + temp[19 - ADD_i];
				}
				else
				{
					c[19 - ADD_i] = c[19 - ADD_i] + temp[19 - ADD_i] - 10;
					ADD_temp = 1;
				}
			}
			else
			{
				if (c[19 - ADD_i] + temp[19 - ADD_i] + 1 < 10)
				{
					c[19 - ADD_i] = c[19 - ADD_i] + temp[19 - ADD_i] + 1;
					ADD_temp = 0;
				}
				else
				{
					c[19 - ADD_i] = c[19 - ADD_i] + temp[19 - ADD_i] + 1 - 10;
					ADD_temp = 1;
				}
			}
		}


	}

	return c;

}

// 比较两个数组之间的大小是否大于 (1为真,0为假)
int a_big_then_b(int a[20],int b[20])
{	
	for (int i = 0; i <= 19; i++)
	{
		if (a[i] >b[i])
		{	
			return 1;
		}
		if (a[i] < b[i])
		{
			return 0;
		}
	}
	return 0;
}

// 比较两个数组之间是否相等(1为真,0为假)
int a_equal_then_b(int a[20], int b[20])
{	
	for (int i = 0; i <= 19; i++)
	{
		if (a[i] == b[i])
		{
			//printf("a[i] = b[i]");
		}
		else 
		{
			return 0;
		}
	}
	return 1;
}

//除法的函数,返回数组指针(a/b)
int* div(int a[20], int b[20])
{	
	static int c[20] = { 0 };
	for (int i = 0; i <= 19; i++)
	{
		c[i] = 0;
	}
	int temp[20] = { 0 }; //向下留的余数的数组
	for (int i = 0; i <= 19; i++)
	{	
		//将之前的temp乘以10(进一位)
		for (int Bubble_time = 0; Bubble_time < 19; Bubble_time++)
		{
			temp[Bubble_time] = temp[Bubble_time + 1];
		}
		temp[19] = 0;
		int temp_compute[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,a[i]};
		int* temp_point;
		temp_point = add(temp, temp_compute);
		for (int temp_counter = 0;temp_counter<=19;temp_counter++)
		{
			temp[temp_counter] = temp_point[temp_counter];
		}
		for (int x = 1; x <= 9; x++)
		{	
			int temp_compute[20] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,x};
			temp_point = rid(b,temp_compute);


			if (a_big_then_b(temp_point,temp))
			{	
				c[i] = x - 1;
				int temp_compute[20] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,x-1};
				temp_point = rid(b, temp_compute);

				int* temp_point_2;
				temp_point_2 = sub(temp, temp_point);
				for (int temp_counter=0;temp_counter<=19;temp_counter++)
				{
					temp[temp_counter] = temp_point_2[temp_counter];
				}
				break;
			}
			if (a_equal_then_b(temp_point, temp))
			{
				c[i] = x;
				for (int temp_counter=0;temp_counter<=19;temp_counter++)
				{
					temp[temp_counter] = 0;
				}
				break;
			}
			if (x == 9)
			{	
				int temp_compute[20] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,a[i]};
				temp_point = add(temp,temp_compute);
				for (int temp_counter = 0; temp_counter <= 19; temp_counter++)
				{
					temp[temp_counter] = temp_point[temp_counter];
				}
			}
		}
	}
	return c;
}


int main()
{	
	int a[20] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,7 };        //第一个数字
	for (int i = 0; i <= 19; i++)										//输出一下
	{
		printf("%d", a[i]);
	}
	printf("\n");
	int b[20] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2 };		//第二个数字
	for (int i = 0; i <= 19; i++)									//输出一下
	{
		printf("%d", b[i]);
	}
	printf("\n");

	int* result;
	result = div(a, b);
	for (int i = 0; i <= 19; i++)
	{
		printf("%d",result[i]);
	}
	return 0;
}

后记

上述算法只是其中的一个思路,可能不是最优的,并且代码中可能有缺陷,请指正,谢谢。

本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议,记得载明出处,(期待)。内容有问题?点此反馈
上一篇
下一篇