大整数运算(算法笔记)

  对于一道A+B的题目,如果A和B的范围在int范围内,那么是很简单的。但是如果A和B都是超过100个数位的整数,那么问题就变得复杂了。

今天,我借鉴《算法笔记》中的算法,总结下大整数运算的技巧。

 

一、大整数的存储

  很简单,使用数组即可。如将整数23581存储到数组中,则有如下数组图:

 

 

 为什么要反过来存储呢?是因为我们在进行整数运算的时候都是从低位到高位进行枚举,这叫做顺位存储。但是顺位存储在读入的时候并不是顺位读入的。

当我们按照字符串%s读入的时候,实际上是逆位存储的,因此在读入之后应当进行逆置处理。

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

1 struct bign{
2     int d[10000];
3     int len;
4 };

  而输入大整数时,一般都是先用字符串读入,然后再把字符串另存至bign结构体。根据以上特点,读入字符串之后,我们应当逆序存储数组中。

 

 1 bign change(char str[]){
    memset(a.d,0,1000*sizeof(int));
2 bign a; 3 a.len = strlen(str); 4 5 int i; 6 for(i=0;i<a.len;i++){ 7 a.d[i] = str[a.len-1-i]; 8 } 9 return a; 10 }

如果要比较两个bign变量的大小,规则也很简单:先判断两者的len大小,如果不相等,则以长的为大;如果相等,则从高位到低位进行判断。

 1 int compare(bign a,bign b){
 2     if(a.len>b.len){
 3         return 1;
 4     }else if(a.len<b.len){
 5         return -1;
 6     }else{
 7         int i;
 8         for(i=a.len-1;i>=0;i--){
 9             if(a.d[i]>b.d[i]){
10                 return 1;
11             }else if(a.d[i]<b.d[i]){
12                 return -1;
13             }
14         }
15     }
16     return 0;
17 }

 

大整数的四则运算(+、-、*、/)

1、高精度加法

模拟小学生手法(记着对结构体中的成员变量初始化0)

 1 bign add(bign a, bign b){
 2     bign c;

      memset(c.d,0,1000*sizeof(int));
      c.len = 0;

 3     int carry = 0;    //carry进位
 4     int i;
 5     for(i=0;i<a.len||i<b.len;i++){//以较长的为界限
 6         int temp = a.d[i]+b.d[i]+carry;
 7         c.d[c.len++] = temp%10;
 8         carry = temp/10;
 9     }
10     if(carry!=0){
11         c.d[c.len++] = carry;
12     }
13     return c;
14 }

2、高精度减法

值得注意的是,在高精度加法中一定存在这样的运算

a=1234,b=-3456;

这样我们其实可以将b转换为正数,然后进行高精度减法,下面介绍高精度减法

 1 bign sub(bign a,bign b){
 2     bign c;
 3     memset(c.d,0,1000*sizeof(int));
 4     c.len = 0;
 5 
 6     int i;
 7     for(i=0;i<a.len||i<b.len;i++){
 8         if(a.d[i]<b.d[i]){
 9             //如果不够减
10             a.d[i+1]--;
11             a.d[i] = a.d[i] + 10;
12         }
13         c.d[c.len++] = a.d[i] - b.d[i];    //减法结果为当前位结果
14 
15     }
16     while(c.len>=2&&c.d[c.len-1] == 0){
17         c.len--;
18     }
19 
20     return c;
21 }

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

3、高精度与低精度的乘法

对乘法的某一步来说,就是以下这样的步骤:

取bign的某位(从低位开始取)与int型整体相乘,再与进位相加,所得结果的个位数作为该位结果,高位部分作为新的进位。

 1 bign multi(bign a,int b){
 2     bign c;
 3     memset(c.d,0,1000*sizeof(int));
 4     c.len=0;
 5     int i;
 6     int carry = 0;
 7     for(i=0;i<a.len;i++){
 8         int temp = a.d[i]*b+carry;
 9         c.d[c.len++] = temp%10;
10         carry = temp/10;
11     }
12 
13     while(carry!=0){
14         //和加法不一样,乘法的进位可能不止一位,因此用while
15         c.d[c.len++] = carry%10;
16         carry = carry/10;
17     }
18     return c;
19 }

4、高精度与低精度的除法

归纳其中某一步的步骤:上一步的余数乘以10加上该步的位,得到该步临时的被除数,将其与被除数比较;如果不够除,则该位商为0;

如果够除,则商为对应的商,余数即为对应的余数。最后注意除法后高位可能有多余的0,要去除它们,但也要保证结果至少有一位数。

 

 1 bign divide(bign a,int b){
 2     bign c;
 3     memset(c.d,0,1000*sizeof(int));
 4     
 5     c.len = a.len;    //被除数的每一位和商的每一位是一一对应的,因此先令长度相等
 6     int i,r = 0;
 7     for(i=a.len-1;i>=0;i--){
 8         r = r*10+a.d[i];    //和上一位遗留的余数结合
 9 
10         if(r<b){
11             //不够除
12             c.d[i] = 0;
13         }else{
14             c.d[i] = r/b;
15             r = r%b;
16         }
17 
18     }
19     while(c.len>=2&&c.d[c.len-1] == 0){
20         c.len--;
21     }
22     return c;
23 }

 

posted @ 2020-03-27 15:36  focusDing  阅读(716)  评论(0编辑  收藏  举报