****使用高精度算法的理由****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做爲商的最高位。次高位等位的處理如後續②③④同理可得。
//高位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