****使用高精度算法的理由****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