高精度算法

  ****使用高精度算法的理由****php

  在C/C++中經常使用的數據類型有int和long long.int佔用一個機器字長,在32位系統中int佔4個字節,範圍爲[-2-31,231-1];long long佔用8個字節,範圍爲[-263,263-1].一旦超過這兩種數據類型的範圍則不可以知足特定數據要求.好比數據2100數量級不可以知足要求,這一類型所以被稱爲高精度或大數類型.高精度有加減乘除類型.c++

  ****高精度加法****算法

  題目:https://www.luogu.com.cn/problem/P1601數組

  求解A+B:(1)輸入兩個正數a,b,輸出和(a,b≤109);(2)輸入兩個正數a,b,輸出和(a,b≤10500
ide

  以下圖(左)所示,算法核心爲紅色筆記部分,既要實現a[i]與b[i]的相加,又要實現進位和本位的輸出考慮.在程序考慮時,若是輸入數爲1234和827這組數據,以下圖(右)將1234的1認爲數組的第0位,827的8認爲數組的第0位,則會致使相加錯誤,正確的操做應如圖中紫色部分所示,對數據進行轉置,將1234中的第0位認爲是4,827中的第0位認爲是7.spa

 

                

   具體代碼以下:3d

 1 #include <bits/stdc++.h>
 2 using namespace std;  3 //採用數組模擬高精度類型 
 4 char s1[505],s2[505];  5 int a[505],b[505],c[505];  6 
 7 int main(void)  8 {  9     int la,lb,lc; 10     memset(c,0,sizeof(c)); 11     scanf("%s",s1); //輸入字符s1 
12     scanf("%s",s2); //輸入字符s2 
13     
14     la = strlen(s1); 15     lb = strlen(s2); 16     
17     //將字符轉換爲數字而且轉置 
18     for(int i = 0; i < la; i++) 19         a[la-i] = s1[i] - '0'; 20     for(int i = 0; i < lb; i++) 21         b[lb-i] = s2[i] - '0'; 22     
23     lc = max(la,lb) + 1; 24     for(int i = 1; i <= lc; i++) 25  { 26         c[i] += a[i] + b[i]; 27         c[i+1] = c[i] / 10; 28         c[i] = c[i] % 10; 29  } 30     
31     if(c[lc] == 0 && lc > 0) 32     //刪除前導0,lc>0是防止0+0=0的狀況 
33         lc--; 34     for(int i = lc; i > 0; i--) 35         printf("%d",c[i]); 36         
37     return 0; 38 } 39  

 

  ****高精度減法****code

  題目:https://www.luogu.com.cn/problem/P2142blog

  求解A-B,須要注意:(1)若是a<b,則須要交換a與b;(2)若是a[i]<b[i],須要高位借1當10使用.get

  具體代碼以下:

 1 #include <bits/stdc++.h>
 2 using namespace std;  3 
 4 char s1[10090],s2[10090],s3[10090];  5 int a[10090],b[10090],c[10090];  6 int flag = 0;  7 bool compare(char s1[],char s2[])  8 {  9     //若是s1>=s2返回T,不然返回F.
10     int u = strlen(s1),v = strlen(s2); 11     if (u != v) return u > v; 12     //u>v返回T,u<v返回F 13     //u=v時進行比較 
14     for(int i = 0; i < u; i++) 15         if(s1[i] != s2[i]) 16             return s1[i] > s2[i]; 17     return true; 18 } 19 
20 int main(void) 21 { 22     int la,lb,lc; 23     scanf("%s",s1); 24     scanf("%s",s2); 25     
26     if(!compare(s1,s2)) 27  { 28     //若是s1<s2則交換,利用複製方式 
29         flag = 1; 30  strcpy(s3,s1); 31  strcpy(s1,s2); 32  strcpy(s2,s3); 33  } 34     
35     la = strlen(s1); 36     lb = strlen(s2); 37     lc = max(la,lb); 38     
39     //字符轉數字並轉置 
40     for(int i = 0; i < la; i++) 41         a[la-i] = s1[i] - '0'; 42     for(int i = 0; i < lb; i++) 43         b[lb-i] = s2[i] - '0'; 44     
45     for(int i = 1; i<= lc; i++) 46  { 47     //若是a[i]<b[i]則借位 
48         if(a[i] < b[i]) 49  { 50             a[i+1]--; 51             a[i] += 10; 52  } 53         c[i] = a[i] - b[i]; 54  } 55     
56     while(c[lc] == 0 && lc > 1) lc--; 57     if(flag == 1) printf("-"); 58     //若是是負數先輸出負號
59     for(int i = lc; i > 0; i--) 60         printf("%d",c[i]); 61     return 0; 62 }

 

  ****高精度乘法****

  題目:求兩個不超過200位的非負整數的積.

  求解a*b,以下圖所示爲a4a3a2a1 * b2b1的計算過程,可見c1=a1*b1,c2=a2*b1+a1*b2,c3=a3*b1+a2*b2,c4=a4*b1+a3*b2,c5=a4*b2,通過分析能夠獲得圖中紫色部分結論,ai*bj對應位爲c_{i+j-1}.乘法運算一樣須要知足加法高精度中的規則.

 

   具體代碼以下:

 1 #include <bits/stdc++.h>
 2 using namespace std;  3 
 4 char s1[2005],s2[2005];  5 int a[2005],b[205],c[2005];  6 
 7 int main(void)  8 {  9     int la,lb,lc; 10     scanf("%s",s1); 11     scanf("%s",s2); 12     
13     la = strlen(s1); 14     lb = strlen(s2); 15     lc = la + lb; 16     
17     for(int i = 0; i < la; i++) 18         a[la-i] = s1[i] - '0'; 19     for(int i = 0; i < lb; i++) 20         b[lb-i] = s2[i] - '0'; 21     
22     for(int i = 1; i <= la; i++) 23  { 24         for(int j = 1; j <= lb; j++) 25  { 26             c[i+j-1] += a[i]*b[j]; 27             c[i+j] = c[i+j-1] / 10; 28             c[i+j-1] %= 10; 29  } 30  } 31     
32     if(c[lc] == 0 && lc > 0) lc --; 33     for(int i = lc; i > 0; i--) 34         printf("%d",c[i]); 35         
36     return 0; 37 }

 

  ****高精度除法****

  題目1:https://www.luogu.com.cn/problem/P1480

  題目2:http://ybt.ssoier.cn:8088/problem_show.php?pid=1308

  A/B須要考慮高精度/高精度和高精度/低精度兩種狀況,高精度除以低精度採用逐位試商法;高精度除以高精度採用減法模擬除法.

  以下圖所示,針對題目1的a÷b,a爲大數(高精度,數組模擬),b爲小數(long long類型)

 

                                           

 

   題目1中的代碼具體以下:

 1 #include <bits/stdc++.h>
 2 using namespace std;  3 
 4 char s1[5005];  5 long long b,c[5005],a[5005],la,lc;  6 
 7 int main(void)  8 {  9     long long x = 0; 10     scanf("%s",s1);//被除數 
11     scanf("%d",&b);//除數
12     
13     la = strlen(s1); 14     //區別於其餘加減乘操做 15     //將如輸入的1234字符依次按順序 16     //放入a數組中 
17     for(int i = 1; i<=la; i++) 18         a[i] = s1[i-1] -'0'; 19         
20     for(int i = 1; i <= la; ++i) 21     //商最多有la位 
22  { 23         c[i] = (x * 10 + a[i]) / b; 24         x = (x * 10 + a[i]) % b; 25  } 26     
27     //刪除前導零 
28     lc = 1; 29     while(c[lc] == 0 && lc < la) 30         lc++; 31     
32     for(int i = lc; i <= la; ++i) 33         printf("%d",c[i]); 34     
35     return 0; 36 }

 

  下面對高精度除以高精度的狀況進行分析,舉個案例解釋,如531518/123的案例,531518爲高精度被除數,123設爲很大的高精度除數,這時能夠採用下圖的①-④步驟進行處理,即將531518和填補至相同位數的123000進行減法處理,通過四次減法後獲得的數的位數要比原來531518的位數即6位小,所以4做爲商的最高位。次高位等位的處理如後續②③④同理可得。

                                             

 

  531518÷123=4321.....35
  其中c的位數爲la-lb+1,上述案例中c的位數至多有4位設爲c1c2c3c4(c4爲高位).
  上述過程能夠用下列僞代碼進行表示:
//高位c[4]的來源
a = 531518; tmp = 123000;(將123左移3位) while a >= tmp: c[4]++; a = a - tmp;(須要用到高精度減法) //c[3]的來源
a=39518; tmp=12300;(將123左移兩位) while a >= tmp: c[3]++; a = a - tmp;(須要用到高精度減法) //c[2]的來源
a=2618; tmp=1230;(將123左移1位) while a >= tmp: c[2]++; a = a - tmp;(須要用到高精度減法) //c[1]的來源
a=158; tmp=123;(將123左移0位) while a >= tmp: c[1]++; a = a - tmp;(須要用到高精度減法) //上述結構能夠用如下循環表示:
a = 531518; for(i=lc;i>=1;i--) { tmp=0; tmp=123 左移 i-1位; while a >= tmp: c[i]++; a = a - tmp;(須要用到高精度減法) }

   最終代碼以下:

 1 //高精度除以高精度求它們的商和餘數  2 //輸入兩個低於300位的正整數
 3  
 4 #include <bits/stdc++.h>
 5 using namespace std;  6 
 7 char s1[305],s2[305];  8 int a[305],b[305],c[305],tmp[305];  9 
10 void init(int *x) 11 { 12     char s[305]; 13     scanf("%s",s); 14     x[0] = strlen(s); 15     for(int i = 0; i < x[0]; i++) 16         x[x[0]-i] = s[i] - '0'; 17     //字符轉爲數字而且倒序存儲 
18 } 19 
20 //輸出 數組第0位存儲長度 
21 void print(int a[]) 22 { 23     if(a[0] == 0) 24  { 25         printf("0"); 26         return; 27  } 28     for(int i = a[0]; i > 0; i--) 29         printf("%d",a[i]); 30     return; 31 } 32 
33 //比較大小 
34 int compare(int a[],int b[]) 35 { 36     if(a[0] > b[0]) 37         return 1; 38     if(a[0] < b[0]) 39         return -1; 40     for(int i = a[0]; i > 0; i--) 41  { 42         if(a[i] > b[i]) 43             return 1; 44         if(a[i] < b[i]) 45             return -1; 46  } 47     return 0; 48 } 49 
50 //減法處理
51 void minu(int a[],int b[]) 52 { 53     for(int i = 1; i <= a[0]; i++) 54  { 55         if(a[i] < b[i]) 56  { 57             a[i+1]--; 58             a[i] = a[i] + 10; 59  } 60         a[i] = a[i] - b[i]; 61  } 62     while(a[a[0]] == 0 && a[0] > 0) 63         a[0]--; 64 } 65 
66 //將p數組移動n位至q數組 
67 void numcpy(int p[],int q[],int n) 68 { 69     for(int i = 1; i <= p[0];i++) 70         q[i+n-1] = p[i]; 71     q[0] = p[0] + n - 1; 72 } 73 
74 
75 int main(void) 76 { 77  init(a); 78  init(b); 79     c[0] = a[0] - b[0] + 1; 80     
81     //代碼的核心 
82     for(int i = c[0]; i >= 1; i--) 83  { 84         memset(tmp,0,sizeof(tmp)); 85  numcpy(b,tmp,i); 86         while(compare(a,tmp) >= 0) 87  { 88             c[i]++; 89  minu(a,tmp); 90  } 91  } 92     
93     while(c[c[0]] ==0 && c[0] > 0) 94         c[0]--; 95     print(c);//
96     printf("\n"); 97     print(a);//最後的a爲餘數 
98     return 0; 99 }

 

****參考文獻****

[1] 麥克老師講算法-高精度算法全套(加減乘除,全網最詳細)https://www.bilibili.com/video/BV1LA411v7mt?p=5

相關文章
相關標籤/搜索