超大整数的加减乘除计算方法

目录

 

问题由来及解决思路:

超大整数的加法运算:

超大整数的减法运算:

超大整数的乘法运算:

超大整数的除法运算:


问题由来及解决思路:

在任何一种编程语言中,基本类型的数据都是具有一定的范围的。例如:在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);
}

猜你喜欢

转载自blog.csdn.net/My_name_is_ZwZ/article/details/83013044