C++少儿编程(17)高精度算法(乘除法)

高精度乘法计算m0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

【描述】输入两个数位不超过100的正整数a、b,计算并输出它俩的积。

【输入】输入两行,第一行输入a,第二行输入b。m0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

【输出】输出一行,a*b的积。m0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

(在计算高精度加法之前,先回忆一下竖式乘法的计算过程,此处略过)m0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

【高精度乘法 - 计算过程】m0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

1、准备工作:m0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

使用字符串类型变量存储a、b两个乘数,创建一维整型数组A、B、C、SUM,使用A、B存储乘数a、乘数b的数位,使用C存储每个数位的乘积,使用SUM累加每次C的结果。m0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

2、预处理:m0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

将a、b的字符串长度分别存入数组A、B的0号元素里,然后分离出字符串中的每个数字,并分别倒序存入A、B数组中。m0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

3、模拟竖式计算:m0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

依次取出B中的每个数位,与A中的每个数位相乘,将结果存入C中,然后将C累加到SUM中。注意:B中数位每向高移动一位,与A相乘的结果C的末尾就要多加一个0。m0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

4、输出结果:m0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

倒序输出数组SUM的每个数位。m0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

以上就是高精度乘法的具体计算步骤。m0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

【高精度乘法 - 示例程序】常规算法m0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

  1. # include <bits/stdc++.h> 
  2. using namespace std; 
  3. // 声明数组A、B,存储两个乘数的数位 
  4. int A[101], B[101]; 
  5. // 数组C存储B中数位与A的乘积(注意长度翻倍) 
  6. int C[202]; 
  7. // 每次得出C,将C累加到SUM中(注意长度与初始值) 
  8. int SUM[202] = {1}; 
  9. // 预处理:记录数位、分离数字、倒序存储 
  10. void fen_li(string s, int a[]) { 
  11.     // 将字符串长度存入数组的0号元素里 
  12.     a[0] = s.size(); 
  13.     // 从字符串中分离出数字,倒序存入数组中 
  14.     for (int i = 1; i <= a[0]; i++) a[i] = s[a[0]-i] - '0'
  15.     return
  16. //声明加法运算函数(将C累加到SUM中) 
  17. void big_plus(int C[], int SUM[]) { 
  18.     SUM[0] = max(C[0], SUM[0]); // SUM[0]存储加数的最高数位 
  19.     int j = 0;                  // 声明变量j存储进位数字,默认为0 
  20.     for (int i = 1; i <= SUM[0]; i++) { 
  21.         SUM[i] += C[i] + j;     // 计算当前数位两个加数与进位之和 
  22.         j = SUM[i] / 10;        // 先计算新的进位 
  23.         SUM[i] %= 10;           // 再处理结果(和)的当前数位 
  24.     } 
  25.     if (j > 0) {            // 如果最后的进位数字大于0 
  26.         SUM[0]++;           // 结果的数位加1 
  27.         SUM[SUM[0]] = j;    // 结果的最高数位设为进位数字 
  28.     } 
  29.     return
  30. // 声明乘法运算函数(B中第n数位与A相乘) 
  31. void big_multiply(int n, int A[]) { 
  32.     // 初始化数组C(所有元素设为0) 
  33.     for (int i = 0; i < 202; i++) C[i] = 0; 
  34.     C[0] = A[0] + n - 1;    // 设定当前乘积的数位 
  35.     int j = 0;              // 进位默认为0 
  36.     for (int i = 1; i <= A[0]; i++) {   // 遍历A中每一位 
  37.         C[i+n-1] = B[n] * A[i] + j;     // 计算B[n]与A[i]的乘积再加进位数 
  38.         j = C[i+n-1] / 10;              // 计算进位数 
  39.         C[i+n-1] %= 10;                 // 计算当前数位 
  40.     } 
  41.     if (j > 0) {        // 如果最后的进位大于0 
  42.         C[0]++;         // 结果的数位加1 
  43.         C[C[0]] = j;    // 结果的最高数位这位进位数字 
  44.     } 
  45.     return
  46. int main() { 
  47.     string a, b; 
  48.     cin >> a >> b;      // 输入高精度乘数a、b的值 
  49.     fen_li(a, A);       // 字符串预处理 
  50.     fen_li(b, B); 
  51.     for (int i = 1; i <= B[0]; i++) {   // 遍历B中的每个数位 
  52.         big_multiply(i, A);      // 将当前遍历到的数与A相乘 
  53.         big_plus(C, SUM);       // 将乘积C累加到SUM中 
  54.     } 
  55.     for (int i = SUM[0]; i > 0; i--) { 
  56.         cout << SUM[i];     // 倒序输出SUM中的数位 
  57.     } 
  58.     cout << endl; 
  59.     return 0; 
 
上述方法显得有些繁琐,通过观察,能不能总结出最终结果的每个的数位的计算公式?如果能,使用解析算法(公式计算)会简单很多。
C++少儿编程(17)高精度算法(乘除法)
通过观察,可以发现c的角标等于同列a的角标加b的角标减1,同时,c的值等于对应a、b的乘积之和,再加上之前的进位,用数学公式表达如下:
m0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库
c[i+j-1] = a[i] * b[j] + c[i+j-1] + jw
有了解析公式,就不用将第二个乘数的每个数位分别与第一个乘数相乘,然后将每次的乘积再累计求和;可以要根据公式,直接计算结果。

【高精度乘法 - 示例程序】解析算法m0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

  1. # include <bits/stdc++.h> 
  2. using namespace std; 
  3. string a, b;        // 声明字符串变量a、b存储两个乘数 
  4. int A[101], B[101];     // 声明数组A、B,存储两个乘数的数位 
  5. int C[202];     // 数组C存储B中数位与A的乘积(注意长度翻倍) 
  6. void fen_li(string s, int a[]) {    // 预处理 
  7.     a[0] = s.size();                // 记录数位、分离数字、倒序存储 
  8.     for (int i = 1; i <= a[0]; i++) a[i] = s[a[0]-i] - '0'
  9.     return
  10. // 声明乘法运算函数:解析算法(A与B相乘,结果存入到C中) 
  11. void big_multiply() { 
  12.     C[0] = A[0] + B[0];     // 设定乘积的数位 
  13.     int jw;         // 声明进位变量 
  14.     for (int i = 1; i <= B[0]; i++) {   // 遍历B中每一位数字 
  15.         jw = 0;     // 每轮内循环开启之前,进位值默认设为0 
  16.         for (int j = 1; j <= A[0]; j++) {   // 遍历A中每一位数字 
  17.             C[i+j-1] += A[j] * B[i] + jw;   // 根据解析公式计算C中数位 
  18.             jw = C[i+j-1] / 10;     // 计算本次的进位值 
  19.             C[i+j-1] %= 10;         // 计算当前数位 
  20.         } 
  21.         C[i+A[0]] = jw;     // 无论进位值是否为0,最后都存储一次进位值 
  22.     } 
  23.     while (C[C[0]] == 0 && C[0] > 1) C[0]--;    // 清空前导0 
  24.     return
  25. int main() { 
  26.     cin >> a >> b;      // 输入高精度乘数a、b的值 
  27.     fen_li(a, A);       // 字符串预处理 
  28.     fen_li(b, B); 
  29.     big_multiply();     // 调用公式执行计算 
  30.     // 倒序输出C中的每个数位 
  31.     for (int i = C[0]; i > 0; i--) cout << C[i]; 
  32.     cout << endl; 
  33.     return 0; 
 

高精度除法计算m0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

高精度除法也是模拟竖式计算的过程,步骤稍微复杂一些,这里就暂且跳过,感兴趣的同学可以自己模拟一下。

近年比赛从来没考过高精度除法,原理都一样。掌握加、减、乘法运算,熟练之后,自然也能写出高精度除法的代码。m0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

 
课后习题
 

题目 1:m0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

输入一个整数n(n<=5000),求n的阶乘。m0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

【参考代码】5000以内的阶乘m0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

  1. #include <bits/stdc++.h> 
  2. using namespace std; 
  3. // 求5000以内的阶乘(低精度与高精度相乘) 
  4. int ret[100000];   // 使用数组存储结果 ret,默认为10万位 
  5. int n, k, jw;   // n为输入数字,k为结果的数位个数,jw表示进位值 
  6. int main() { 
  7.     k = 1; 
  8.     ret[1] = 1; 
  9.     cin >> n; 
  10.     // 特殊情况处理 
  11.     if (n < 0) cout << "输入有误" << endl; 
  12.     if (n < 2) cout << 1 << endl; 
  13.     // 循环2~n之间的每个数,分别与ret相乘(低精度乘以高精度) 
  14.     for (int i = 2; i <= n; i++) { 
  15.         jw = 0;     // 每轮内层循环开启之前,都要将进位重置为0 
  16.         for (int j = 1; j <= k; j++) {  // 遍历ret的每个数位 
  17.             int tmp = ret[j] * i + jw;  // 将相乘之积与进位之和存入tmp临时变量中 
  18.             jw = tmp / 10;              // 计算当前进位值 
  19.             ret[j] = tmp % 10;          // 计算当前结果数位 
  20.         } 
  21.         while (jw > 0) {        // 每次内层循环结束之后,只要进位值大于0 
  22.             k++;                // 就将数位个数加1 
  23.             ret[k] = jw % 10;   // 将第k为数字设为进位的末位数字 
  24.             jw /= 10;           // 去除进位值的末位数字 
  25.         } 
  26.     } 
  27.     // 输出结果:倒序输出数组ret中的元素 
  28.     for (int i = k; i > 0; i--) cout << ret[i]; 
  29.     cout << endl; 
  30.     return 0; 

题目 2:m0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

输入a、b两个正整数,计算 a ^ b。(0<a<10000, 0<b<200)m0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

【参考代码】计算 a ^ bm0N100150满分答卷(100150.com)-青少年编程等级考试及竞赛题库

  1. #include <bits/stdc++.h> 
  2. using namespace std; 
  3. // 求a^b(a、b均为低精度),低精度与高精度的乘法 
  4. int ret[100000]; // 使用数组存储结果 ret,默认为10万位 
  5. int a, b, k, jw;    // a、b为输入数字,k为结果的数位个数,jw表示进位值 
  6. int main() { 
  7.     k = 1;          // 默认数位为 1 
  8.     ret[1] = 1;     // 第一位的数位值为 1 
  9.     cin >> a >> b;  // 输入a、b、的值 
  10.     // 特殊情况处理 
  11.     if (b < 0) 
  12.         cout << "输入有误" << endl; 
  13.     // 循环b次,分别与ret相乘(低精度乘以高精度) 
  14.     for (int i = 1; i <= b; i++) { 
  15.         jw = 0; // 每轮内层循环开启之前,都要将进位重置为0 
  16.         for (int j = 1; j <= k; j++) {  // 遍历ret的每个数位 
  17.             int tmp = ret[j] * a + jw; // 将相乘之积与进位之和存入tmp临时变量中 
  18.             jw = tmp / 10;             // 计算当前进位值 
  19.             ret[j] = tmp % 10;         // 计算当前结果数位 
  20.         } 
  21.         while (jw > 0) {      // 每次内层循环结束之后,只要进位值大于0 
  22.             k++;              // 就将数位个数加1 
  23.             ret[k] = jw % 10; // 将第k为数字设为进位的末位数字 
  24.             jw /= 10;         // 去除进位值的末位数字 
  25.         } 
  26.     } 
  27.     // 输出结果:倒序输出数组ret中的元素 
  28.     for (int i = k; i > 0; i--) cout << ret[i]; 
  29.     cout << endl; 
  30.     return 0; 

关 键 词

高精度算法

相关教程

提示声明

  • 免责声明:本站资源均来自网络或者用户投稿,仅供用于学习和交流:如有侵权联系删除!

猜你喜欢