超大整数的加减乘除计算方法
目录
问题由来及解决思路:
在任何一种编程语言中,基本类型的数据都是具有一定的范围的。例如:在Java中长整型long占有8个字节,即64位。那么当两个数足够大,大到无法用long来定义的时候,如何进行他们的加减乘除这种简单的运算?
在编程语言中用于存储超级大的数据我们首先就会想到数组。也就是用数组的方式进行存储,然后对数组中的数据进行加减乘除的操作。
例如:
思路:数组中的每一位都相对应的加减,需要进位或借位的就使用一个变量进行记录。
超大整数的加法运算:
以下是加法运算函数:
const int N=4;//定义数组的长度为4 也可以更长,这个看自己计算的数据的大小
static int carry=0;//定义初始进位值
//加法函数 a,b,c是用户调用此函数时传来的数组名
void add(int *a, int *b, int *c)
{int i;
//数组的高位存储的数据的低位 所以我们从i=N-1开始循环
for(i = N - 1; i >= 0; i--)
{c[i] = a[i] + b[i] + carry;
carry=c[i]/10000;
c[i]=c[i]%10000;
}
}
其就是在模拟平时的加法运算过程。按照低位到高位的顺序对应的位相加,如果有进位就使用carry进行保存,保存之后当进入下一个循环也就是其相邻的高位进行相加时在将carry加到高位上。
以下是得出加法结果存在于c[ ]之后的输出函数:
void print(int *c,int k)//参数k指数组的长度
{int i;
for (i=0;i<k;i++)
printf("%04d",c[i]);//不足四位的,前面补0输出
printf("\n");
}
这里一定要注意的一点就是:我们在进行加法运算的时候,数组每一个地方存储的数不一定是4位,例如上边例子里面的a[ ]数组中,有一个地方存储的是123,b[ ]数组中有一个地方存储的是456,在执行加法运算的时候这个是不影响的,但是输出的时候我们要在它的前面补0。这也算是add函数使用时候的一个规定吧,就是说数组的每一位上都要存储4位数。如果不这样子规定的话,用户想在哪里存储多少就存储多少的话就会乱掉。而且add函数中/10000和%1000也就没有了它的道理所在(与N=4无关,N=4是规定这个数组长度,而我们这里说的4是指数组中每一位上必须有4个数) 为了更好的理解这个问题,我们写个main方法去调用一下这个add函数:
int main()
{//1234034523670098+213654305769786
int i,d=123,a[N]={1234,345,2367,98},b[N]={213,6543,576,9786},c[N];
//将c[]清零
for (i=0;i<N;i++)
{c[i]=0;}
//调用add函数
add(a,b,c);
if (carry==1)
printf("%d",carry);
//调用print函数
print(c,N);
}
超大整数的减法运算:
以下是减法运算函数:
const int N=4;//定义数组的长度为4 也可以更长,这个看自己计算的数据的大小
int borrow=0;//用于存储借位的变量
void sub(int *a, int *b, int *c)
{int i;
for(i =N- 1; i >= 0; i--)
{c[i] = a[i] - b[i] - borrow;
if(c[i] >= 0)
borrow = 0;
else // 借位
{c[i] = c[i] + 10000;
borrow = 1;}
}
}
则上面的sub函数就是模拟的下面这种减法运算的过程。让数组对应的每一组数据进行减法运算,然后将借位borrow记下,如果有借位,在下一次循环也就是它的相邻的高位的数据进行减法运算时,将borrow减下来。就是我们平时做减法运算时候的一个过程。
以下是打印输出函数(与加法运算时的打印输出函数相同):
void print(int *c,int k)//参数k指数组的长度
{int i;
for (i=0;i<k;i++)
printf("%04d",c[i]);
printf("\n");
}
我们写一个main对其进行调用:
int main()
{int i,a[N]={1234,5678,3344,5566},b[N]={4321,8765,8899,7766},c[N];
for (i=0;i<N;i++)
{c[i]=0;}
sub(a,b,c);
if (borrow==0)
print(c,N);
//对于执行完sub方法后的进位进行判断,如果borrow!=0,表示a-b<0
else
{borrow=0;
sub(b,a,c);printf("-");print(c,N);
}
}
超大整数的乘法运算:
以下是乘法运算的函数:
const int N=4;
static int carry=0;//存储进位的变量
void mul(int *a, int b, int *c)
{ // b 为乘数且其数值较小,不属于大整数的范围
int i, tmp;
carry = 0;
for(i =N- 1; i >=0; i--) {
tmp = a[i] * b + carry;
c[i] = tmp % 10000;
carry = tmp / 10000;
}
}
以下是打印输出函数:
void print(int *c,int k)
{int i;
for (i=0;i<k;i++)
printf("%04d",c[i]);
printf("\n");
}
我们写一个main对其进行测试:
int main()
{int i,d=123,a[N]={1234,5678,3344,5566},c[N];
for (i=0;i<N;i++)
{c[i]=0;}
mul(a,d,c);
//执行完mul后,如果carry!=0表示最高位上有了进位,那么就要先把carry打印出来再调用print函数
if (carry!=0)
printf("%d",carry);
print(c,N);
}
超大整数的除法运算:
以下是除法运算的函数:
const int N=4;
int remain=0;
void div(int *a, int b, int *c)
{
int i, tmp;
//除法函数与其他三种不同的是它循环从i=0开始,因为a[0]处存储的是数据的高位,而除法是从高位开始算起
for(i =0; i <N; i++)
{
tmp = a[i] + remain;
c[i] = tmp / b;
remain = (tmp % b) * 10000;
}
}
以下是手动进行除法运算的过程:
由以上除法运算过程大家可以看出除法是从高位向低位进行。为了更好的理解上边的div函数,可以对其过程进行模拟,例如使用12347851 / 4列一个竖式。由实践可知:tmp表示每次 / 4的那个数,而没有除尽的话,是要把这个余数加在后面的数上面接着/4,而remain就是用于存储余数的变量。
输出函数:
void print(int *c,int k)
{int i;
for (i=0;i<k;i++)
printf("%04d",c[i]);
printf("\n");
}
写一个main函数对其进行测试:
int main()
{int i,d=123,a[N]={1234,5678,3344,5566},c[N];
for (i=0;i<N;i++)
{c[i]=0;}
div(a,d,c);
print(c,N);
}