大數的四則運算(加法、減法、乘法、除法)


前言:

    在計算機中數字表示的范圍是有限制的,比如我們熟知的 int、float、double 等數據類型所能表示的范圍都是有限的,如果我們要對位數達到幾十位、幾百位、上千位的大整數進行計算,這些數據類型顯然不能滿足我們的要求,因此我們需要通過算法來實現這些功能。

 

1、大數加法

    兩個大數我們可以用數組來保存,然后在數組中逐位進行相加,再判斷該位相加后是否需要進位,為了方便計算,我們將數字的低位放在數組的前面,高位放在后面。

下面是兩個正的大整數相加算法的C語言參考代碼:

 1 #include<stdio.h>
 2 #include<string.h>
 3 
 4 #define MAX 1000    // 大數的最大位數 
 5 
 6  
 7 /*
 8   大數加法 
 9   參數: 
10   num1為第一個大數,用字符數組保存
11   num2為第二個大數
12   sum數組保存相加的結果  即:num1+num2=sum
13   返回值:返回數組sum的有效長度,即計算結果的位數 
14  */
15 int Addition(char num1[], char num2[], int sum[])
16 {
17     int i, j, len;
18     int n2[MAX] = {0};
19     int len1 = strlen (num1); // 計算數組num1的長度,即大數的位數 
20     int len2 = strlen (num2); // 計算數組num2的長度,即大數的位數 
21 
22     len = len1>len2 ? len1 : len2; // 獲取較大的位數
23     //將num1字符數組的數字字符轉換為整型數字,且逆向保存在整型數組sum中,即低位在前,高位在后
24     for (i = len1-1, j = 0; i >= 0; i--, j++) 
25         sum[j] = num1[i] - '0';
26     // 轉換第二個數 
27     for (i = len2-1, j = 0; i >= 0; i--, j++)
28         n2[j] = num2[i] - '0';
29     // 將兩個大數相加 
30     for (i = 0; i <= len; i++)
31     {
32         sum[i] += n2[i];  // 兩個數從低位開始相加 
33         if (sum[i] > 9)   // 判斷是否有進位 
34         {   // 進位 
35             sum[i] -= 10;
36             sum[i+1]++;
37         }
38     }
39     if(sum[len] != 0)  // 判斷最高位是否有進位 
40         len++;
41     return len;   // 返回和的位數 
42 }
43 
44 int main()
45 {
46     int i, len;
47     int sum[MAX] = {0}; // 存放計算的結果,低位在前,高位在后,即sum[0]是低位 
48     char num1[] = "1234567891234567891234"; // 第一個大數 
49     char num2[] = "2345678912345678913345"; // 第二個大數 
50     len = Addition(num1, num2, sum);    // 兩數相加 
51     printf("%s\n  +\n%s\n  =\n", num1, num2);
52     // 反向輸出求和結果
53     for (i = len-1; i >= 0; i--)
54         printf("%d", sum[i]);
55     printf("\n"); 
56     return 0;
57 }

 

2、大數減法

    相減算法也是從低位開始減的。先要判斷被減數和減數哪一個位數長,若被減數位數長是正常的減法;若減數位數長,則用被減數減去減數,最后還要加上負號;當兩數位數長度相等時,最好比較哪一個數字大,否則負號處理會很繁瑣;處理每一項時要,如果前一位相減有借位,就先減去上一位的借位,無則不減,再去判斷是否能夠減開被減數,如果減不開,就要借位后再去減,同時置借位為1,否則置借位為0。

下面是C語言參考代碼:

  1 #include<stdio.h>
  2 #include<string.h>
  3 
  4 #define MAX 1000    // 大數的最大位數 
  5 
  6  
  7 /*
  8   大數減法 
  9   參數: 
 10   num1為被減數,用字符數組保存
 11   num2為減數 
 12   sum數組保存相減的結果   即:num1-num2=sum
 13   返回值:返回數組sum的有效長度,即計算結果的位數 
 14  */
 15 int Subtraction(char num1[], char num2[], int sum[])
 16 {
 17     int i, j, len, blag;
 18     char *temp;
 19     int n2[MAX] = {0};
 20     int len1 = strlen(num1); // 計算數組num1的長度,即大數的位數 
 21     int len2 = strlen(num2); // 計算數組num2的長度,即大數的位數
 22     
 23     // 在進行減法之前要進行一些預處理 
 24     blag = 0; // 為0表示結果是正整數,為1表示結果是負整數 
 25     if(len1 < len2) // 如果被減數位數小於減數
 26     {
 27         blag = 1; // 標記結果為負數
 28         // 交換兩個數,便於計算 
 29         temp = num1;
 30         num1 = num2;
 31         num2 = temp;
 32         len = len1;
 33         len1 = len2;
 34         len2 = len;
 35     }
 36     else if(len1 ==len2) // 如果被減數的位數等於減數的位數
 37     {  
 38         // 判斷哪個數大 
 39         for(i = 0; i < len1; i++)
 40         {
 41             if(num1[i] == num2[i])
 42                 continue;
 43             if(num1[i] > num2[i])
 44             {
 45                 blag = 0; // 標記結果為正數 
 46                 break;
 47             } 
 48             else
 49             {
 50                 blag = 1; // 標記結果為負數 
 51                 // 交換兩個數,便於計算 
 52                 temp = num1;
 53                 num1 = num2;
 54                 num2 = temp;
 55                 break;
 56             } 
 57         } 
 58     }
 59     len = len1>len2 ? len1 : len2; // 獲取較大的位數
 60     //將num1字符數組的數字轉換為整型數且逆向保存在整型數組sum中,即低位在前,高位在后
 61     for (i = len1-1, j = 0; i >= 0; i--, j++) 
 62         sum[j] = num1[i] - '0';
 63     // 轉換第二個數 
 64     for (i = len2-1, j = 0; i >= 0; i--, j++)
 65         n2[j] = num2[i] - '0';
 66     // 將兩個大數相減 
 67     for (i = 0; i <= len; i++)
 68     {
 69         sum[i] = sum[i] - n2[i]; // 兩個數從低位開始相減 
 70         if (sum[i] < 0)   // 判斷是否有借位 
 71         {    // 借位 
 72             sum[i] += 10;
 73             sum[i+1]--;
 74         }
 75     }
 76     // 計算結果長度 
 77     for (i = len1-1; i>=0 && sum[i] == 0; i--)
 78         ;
 79     len = i+1;
 80     if(blag==1)
 81     {
 82         sum[len] = -1;  // 在高位添加一個-1表示負數 
 83         len++;
 84     }
 85     return len;   // 返回結果的位數 
 86 }
 87 
 88 int main()
 89 {
 90     int i, len;
 91     int sum[MAX] = {0}; // 存放計算的結果,低位在前,高位在后,即sum[0]是低位 
 92     char num1[] = "987654321987654321"; // 第一個大數 
 93     char num2[] = "123456789123456789"; // 第二個大數 
 94     len = Subtraction(num1, num2, sum);    // 兩數相減 
 95     // 輸出結果
 96     printf("%s\n  -\n%s\n  =\n", num1, num2);
 97     if(sum[i=len-1] < 0) // 根據高位是否是-1判斷是否是負數
 98     {
 99         printf("-"); // 輸出負號
100         i--;
101     }
102     for (; i >= 0; i--)
103         printf("%d", sum[i]);
104     printf("\n"); 
105     return 0;
106 } 

 

3、大數乘法

    首先說一下乘法計算的算法,從低位向高位乘,在豎式計算中,我們是將乘數第一位與被乘數的每一位相乘,記錄結果,之后,用第二位相乘,記錄結果並且左移一位,以此類推,直到計算完最后一位,再將各項結果相加,得出最后結果。

    計算的過程基本上和小學生列豎式做乘法相同。為了編程方便,並不急於處理進位,而是將進位問題留待最后統一處理。

    總結一個規律: 即一個數的第i 位和另一個數的第j 位相乘所得的數,一定是要累加到結果的第i+j 位上。這里i, j 都是從右往左,從0 開始數。
    ans[i+j] = a[i]*b[j];

    另外注意進位時要處理,當前的值加上進位的值再看本位數字是否又有進位;前導清零。

下面是C語言的兩個正大數相乘的參考代碼:

 1 #include<stdio.h>
 2 #include<string.h>
 3 
 4 #define MAX 1000    // 大數的最大位數 
 5 
 6  
 7 /*
 8   大數乘法 
 9   參數: 
10   num1為第一個因數,用字符數組保存
11   num2為第二個因數
12   sum數組保存相乘的結果  即:num1*num2=sum
13   返回值:返回數組sum的有效長度,即計算結果的位數 
14  */
15 int Multiplication(char num1[],char num2[], int sum[])
16 {
17     int i, j, len, len1, len2;
18     int a[MAX+10] = {0};
19     int b[MAX+10] = {0};
20     int c[MAX*2+10] = {0};
21     
22     len1 = strlen(num1);
23     for(j = 0, i = len1-1; i >= 0; i--) //把數字字符轉換為整型數 
24         a[j++] = num1[i]-'0';
25     len2 = strlen(num2);
26     for(j = 0, i = len2-1; i >= 0; i--)
27         b[j++] = num2[i]-'0';
28     
29     for(i = 0; i < len2; i++)//用第二個數乘以第一個數,每次一位 
30     {
31         for(j = 0; j < len1; j++)
32         {
33             c[i+j] += b[i] * a[j]; //先乘起來,后面統一進位
34         }
35     }
36     
37     for(i=0; i<MAX*2; i++) //循環統一處理進位問題
38     {
39         if(c[i]>=10)
40         {
41             c[i+1]+=c[i]/10;
42             c[i]%=10;
43         }
44     }
45 
46     for(i = MAX*2; c[i]==0 && i>=0; i--); //跳過高位的0
47     len = i+1; // 記錄結果的長度 
48     for(; i>=0; i--)
49         sum[i]=c[i];
50     return len; 
51 }
52 
53 int main()
54 {
55     int i, len;
56     int sum[MAX*2+10] = {0}; // 存放計算的結果,低位在前,高位在后,即sum[0]是低位 
57     char num1[] = "123456789123456789"; // 第一個大數 
58     char num2[] = "123456789123456789"; // 第二個大數 
59     len = Multiplication(num1, num2, sum);
60     // 輸出結果
61     printf("%s\n  *\n%s\n  =\n", num1, num2);
62     for(i = len-1; i>=0; i--)
63         printf("%d", sum[i]); 
64     printf("\n"); 
65     return 0;
66 } 

 

4、大數除法

    大數除法是四則運算里面最難的一種。不同於一般的模擬,除法操作不是模仿手工除法,而是利用減法操作來實現的。其基本思想是反復做除法,看從被除數里面最多能減去多少個除數,商就是多少。逐個減顯然太慢,要判斷一次最多能減少多少個整數(除數)的10的n次方。

以7546除以23為例:

    先用7546減去23的100倍,即減去2300,可以減3次,余下646,此時商就是300 (300=100*3);

    然后646減去23的10倍,即減去230,可以減2次,余下186,此時商就是320 (320=300+10*2);

    然后186減去23,可以減8次,余下2,此時商就是328 (328=320+1*8);

    因為2除以23的結果小於1,而我們又不用計算小數點位,所以不必再繼續算下去了。

下面是C語言的兩個正大數相除的參考代碼,計算結果中沒有小數:

  1 #include<stdio.h>
  2 #include<string.h> 
  3 #define MAX 1000    // 大數的最大位數 
  4 
  5 // 注: 
  6 // 本代碼在以下博客代碼中進行修改: 
  7 // http://www.cnblogs.com/javawebsoa/archive/2013/08/01/3231078.html
  8 // 
  9 
 10 
 11 /*
 12   函數SubStract功能:
 13   用長度為len1的大整數p1減去長度為len2的大整數p2
 14   結果存在p1中,返回值代表結果的長度
 15   不夠減:返回-1 , 正好夠:返回0
 16 */ 
 17 int SubStract(int *p1, int len1, int *p2, int len2)
 18 {
 19     int i;
 20     if(len1 < len2)
 21         return -1;
 22     if(len1 == len2 )
 23     {                        // 判斷p1 > p2
 24         for(i = len1-1; i >= 0; i--)
 25         {
 26             if(p1[i] > p2[i])   // 若大,則滿足條件,可做減法
 27                 break;
 28             else if(p1[i] < p2[i]) // 否則返回-1
 29                 return -1;
 30         }
 31     }
 32     for(i = 0; i <= len1-1; i++)  // 從低位開始做減法
 33     {
 34         p1[i] -= p2[i];         // 相減 
 35         if(p1[i] < 0)           // 若是否需要借位
 36         {   // 借位 
 37             p1[i] += 10;
 38             p1[i+1]--;
 39         }
 40     }
 41     for(i = len1-1; i >= 0; i--)  // 查找結果的最高位
 42     {
 43         if( p1[i] )             //最高位第一個不為0
 44             return (i+1);       //得到位數並返回
 45     } 
 46     return 0;                   //兩數相等的時候返回0
 47 }
 48 
 49 
 50 /*
 51   大數除法---結果不包括小數點 
 52   num1 被除數
 53   num2 除數 
 54   sum  商,存放計算的結果,即:num1/num2=sum
 55   返回數組sum的有效長度,即商的位數 
 56 */ 
 57 int Division(char num1[], char num2[], char sum[])
 58 {
 59     int k, i, j;
 60     int len1, len2, len=0;     //大數位數
 61     int dValue;                //兩大數相差位數
 62     int nTemp;                 //Subtract函數返回值
 63     int num_a[MAX] = {0};      //被除數
 64     int num_b[MAX] = {0};      //除數
 65     int num_c[MAX] = {0};      //
 66 
 67     len1 = strlen(num1);       //獲得大數的位數
 68     len2 = strlen(num2);
 69     
 70     //將數字字符轉換成整型數,且翻轉保存在整型數組中 
 71     for( j = 0, i = len1-1; i >= 0; j++, i-- )
 72         num_a[j] = num1[i] - '0';
 73     for( j = 0, i = len2-1; i >= 0; j++, i-- )
 74         num_b[j] = num2[i] - '0';
 75 
 76     if( len1 < len2 )          //如果被除數小於除數,直接返回-1,表示結果為0
 77     {
 78         return -1;
 79     }
 80     dValue = len1 - len2;      //相差位數
 81     for (i = len1-1; i >= 0; i--)    //將除數擴大,使得除數和被除數位數相等
 82     {
 83         if (i >= dValue)
 84             num_b[i] = num_b[i-dValue];
 85         else                         //低位置0
 86             num_b[i] = 0;
 87     }
 88     len2 = len1;
 89     for(j = 0; j <= dValue; j++ )    //重復調用,同時記錄減成功的次數,即為商
 90     {
 91         while((nTemp = SubStract(num_a, len1, num_b+j, len2-j)) >= 0)
 92         {
 93             len1 = nTemp;            //結果長度
 94             num_c[dValue-j]++;       //每成功減一次,將商的相應位加1
 95         }
 96     }
 97     // 計算商的位數,並將商放在sum字符數組中 
 98     for(i = MAX-1; num_c[i] == 0 && i >= 0; i-- );  //跳過高位0,獲取商的位數 
 99     if(i >= 0)
100         len = i + 1; // 保存位數 
101     for(j = 0; i >= 0; i--, j++)     // 將結果復制到sum數組中 
102         sum[j] = num_c[i] + '0';
103     sum[j] = '\0';   // sum字符數組結尾置0 
104     return len;      // 返回商的位數 
105 } 
106 
107 
108 int main()
109 {
110     int i;
111     int len;                // 商的位數
112     char num1[MAX] = "1234567899876543210";   // 第一個大數
113     char num2[MAX] = "20160415123025";              // 第二個大數
114     char sum[MAX] = {0};    // 計算結果 
115 
116     //scanf("%s", num1);      //以字符串形式讀入大數
117     //scanf("%s", num2);
118     
119     len = Division(num1, num2, sum); 
120     
121     //輸出結果
122     printf("%s\n  ÷\n%s\n  =\n", num1, num2);
123     if( len>=0 )
124     {
125         for(i = 0; i < len; i++ )
126             printf("%c", sum[i]);
127     }
128     else
129     {
130         printf("0");
131     }
132     printf("\n");
133     
134     return 0;
135 }

 

5、使用Java提供的類

    在Java中提供了BigInteger類和BigDecimal類,分別用來處理大整數和大浮點數,我們只要調用里面提供的方法就能很方便的進行大數的四則運算,具體實現可參考:http://www.cnblogs.com/wuqianling/p/5410218.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM