很多人在刚接触高精度算法的时候可能和我有一样的疑问,明明用int或者再大一丢丢的longlong就能储存的数据,为什么非要用高精度算法。
这是因为普通基本数据类型存储数据的时候是有大小限制的,比如我们常用的int-->他的表示范围是(-2^31,2^31-1)大约是10^9数量级,那么如果我想表示10^11数量级的数字怎么办?有人说可以用longlong它大概是10^18次方量级,但如果我要存储的比10^18量级还大的数据怎么办?这也需要用高精度算法了
那么高精度算法是如何储存想10^11次方这样量级的数据的那,其实很简单,用的就是一个整型数组,因为我们知道如果我们的数组开在全局区的话,那么它的空间可以非常非常的大,反正你想表示的大数它肯定能存下。
初步了解了高精度的大概模样之后,我来介绍一下高精度算法的四大模块
如果用整形数组去接收我们的高精度数,整形数组会认为他是一个数,把它都存储在下标0的位置,会溢出
所以必须用字符数组去接收,它会把高精度数看出多个字符的形式,而且还可以很轻松用strlen求出长度
这样做的话可以模拟整形数组的第一位就是个位,第二位就是十位一次类推
因为我们在算加减乘的时候都是先算个位,然后十位,一次类推,这样做可以方便计算
俩个数相加之后的长度最长也不会超过他俩长度的最大值+1
设a,b位整形数组存储的高精度数,c位俩个高精度数相加后的结果
那么
c[i]=a[i]+b[i]+c[i] //c的第i位应该等于a的第i位+b的第i位再加上第i位的进位
c[i+1]=c[i]/10;
c[i]=c[i]%10;
求两个不超过200位的非负整数的和。
有两行,每行是一个不超过200位的非负整数,可能有多余的前导0。
一行,即相加后的结果。结果里不能有多余的前导0,即如果结果是342,那么就不能输出为0342。
22222222222222222222 33333333333333333333
55555555555555555555
代码实现
#include using namespace std; const int N = 2e2 + 5; char sa[N], sb[N]; int a[N], b[N], c[N]; void CharToInt(char sa[], int a[]) { for (int i = 1; i <= a[0]; i++) { a[i] = sa[a[0] - i] - '0'; } } void GJD_Add(int a[], int b[], int c[]) { for (int i = 1; i <= c[0]; i++) { c[i] = a[i] + b[i] + c[i]; c[i + 1] = c[i] / 10; c[i] = c[i] % 10; } } void Delete_frontZero(int c[]) { while (c[0] >= 2 && c[c[0]] == 0) { c[0]--; } } void Show(int c[]) { for (int i = c[0]; i >= 1; i--) { cout << c[i]; } } int main() { cin >> sa >> sb;//用字符数组接收高精度数 a[0] = strlen(sa);//a[0]表示高精度数sa的位数 b[0] = strlen(sb);//b[0]表示高精度数sb的位数 CharToInt(sa, a);//把字符数组sa逆序转化位整形数组 CharToInt(sb, b);//把字符数组sb逆序转化位整形数组 c[0] = max(a[0], b[0]) + 1;//c长度 GJD_Add(a, b, c);//模拟高精度加法 Delete_frontZero(c);//删除前导0 Show(c);//输出 return 0; }
设a,b位整形数组存储的高精度数,c位俩个高精度数相减后的结果
那么
先判断a[i]和b[i]的大小关系,如果a[i]
if (a[i] < b[i]) { a[i + 1]--;//借1 c[i] = a[i] - b[i] + 10;//当10 } else c[i] = a[i] - b[i];
求两个大的正整数相减的差。
共2行,第1行是被减数a,第2行是减数b(a > b)。每个大整数不超过200位,不会有多余的前导零。
一行,即所求的差。
9999999999999999999999999999999999999 9999999999999
9999999999999999999999990000000000000
#include using namespace std; const int N = 2e2 + 5; char sa[N], sb[N]; int a[N], b[N], c[N]; void CharToInt(char sa[], int a[]) { for (int i = 1; i <= a[0]; i++) { a[i] = sa[a[0] - i] - '0'; } } void GJD_reduce(int a[], int b[], int c[]) { for (int i = 1; i <= c[0]; i++) { if (a[i] < b[i]) { a[i + 1]--;//借1 c[i] = a[i] - b[i] + 10;//当10 } else c[i] = a[i] - b[i]; } } void Delete_frontZero(int c[]) { while (c[0] >= 2 && c[c[0]] == 0) { c[0]--; } } void Show(int c[]) { for (int i = c[0]; i >= 1; i--) { cout << c[i]; } } int main() { cin >> sa >> sb; a[0] = strlen(sa); b[0] = strlen(sb); CharToInt(sa, a); CharToInt(sb, b); c[0] = max(a[0], b[0]); GJD_reduce(a, b, c); Delete_frontZero(c); Show(c); return 0; }
for (int i = 1; i <= a[0];i++) { for (int j = 1; j <= b[0];j++) { c[i + j - 1] += a[i] * b[j]; c[i + j] += c[i + j - 1] / 10; c[i + j - 1] = c[i + j - 1] % 10; } }
#include using namespace std; const int N = 2e2 + 5; char sa[N], sb[N]; int a[N], b[N], c[N]; void CharToInt(char sa[], int a[]) { for (int i = 1; i <= a[0]; i++) { a[i] = sa[a[0] - i] - '0'; } } void GJD_Multiply(int a[], int b[], int c[]) { for (int i = 1; i <= a[0]; i++) { for (int j = 1; j <= b[0]; j++) { c[i + j - 1] += a[i] * b[j]; c[i + j] += c[i + j - 1] / 10; c[i + j - 1] = c[i + j - 1] % 10; } } } void Delete_frontZero(int c[]) { while (c[0] >= 2 && c[c[0]] == 0) { c[0]--; } } void Show(int c[]) { for (int i = c[0]; i >= 1; i--) { cout << c[i]; } } int main() { cin >> sa >> sb; a[0] = strlen(sa); b[0] = strlen(sb); CharToInt(sa, a); CharToInt(sb, b); c[0] = a[0] + b[0]; GJD_Multiply(a, b, c); Delete_frontZero(c); Show(c); return 0; }
它的算法实现思路与之前的略有不同,之前是俩已经有数据的数组相乘保存再另一个数组里面
而他刚开始数组里面是空的,经过一次又一次的循环它里面的数据变成了高精度数据,但是与它相乘的始终都是低精度
假设刚开始a[0]长度位1,循环结束之后,jw进位数可能是一个很大的数,我们要把它平铺开!!!!!!!!核心!!!!!!!!!!
for (j = 1; j <= a[0]; j++) { a[j] = a[j] * i + jw; jw = a[j] / 10; a[j] = a[j] % 10; } while (jw > 0) { a[j++] = jw % 10; jw /= 10; a[0]++; }
求1000010000以内n�的阶乘。
只有一行输入,整数n�(0≤n≤100000≤�≤10000)。
一行,即n!�!的值。
4
24
#includeusing namespace std; const int N = 4e4 + 5; char sa[N]; int a[N], len, n, jw, j; int main() { cin >> n;//4 len = 1; a[1] = 1; for (int i = 1; i <= n; i++) { jw = 0; for (j = 1; j <= len; j++) { a[j] = a[j] * i + jw; jw = a[j] / 10; a[j] = a[j] % 10; } while (jw > 0) { a[j++] = jw % 10; jw /= 10; len++; } while (len >= 2 && a[len] == 0) { len--; } } for (int i = len; i >= 1; i--) { cout << a[i]; } cout << endl; return 0; }
略!!!!!!!
模拟小学算术的过程可以得到
输入一个大于0的大整数N,长度不超过100位,要求输出其除以13得到的商和余数。
一个大于0的大整数,长度不超过100位。
两行,分别为整数除法得到的商和余数。
2132104848488485
164008065268345 0
#include using namespace std; const int N = 2e5 + 5; char sa[N]; int a[N], c[N],lena,k; int Chufa13(int a[],int c[]) { int x = 0; c[0] = a[0]; for (int i = 1;i<=a[0];i++){ c[i] = (x * 10 + a[i]) / 13; x = (x * 10 + a[i]) %13; } return x; } void Reverse(int c[]) { int i, j; for (i = 1, j = c[0]; j > i;j--,i++) { swap(c[i], c[j]); } } void DeleteZero(int c[]) { while (c[0] >= 1&&c[c[0]]==0) { c[0]--; } } int main() { int flag = 0; cin >> sa; a[0] = strlen(sa); for (int i = 1; i <= a[0]; i++) { a[i] = sa[i-1]-'0'; } int yushu=Chufa13(a, c); Reverse(c); DeleteZero(c); for (int i = c[0]; i >= 1;i--) { cout << c[i]; } cout << endl; cout << yushu; return 0; }