当前位置:   article > 正文

高精度乘法_高精度乘法核心算法

高精度乘法核心算法
1.高精度乘法原理

高精度乘法问题主要利用了乘法原理,利用字符数组存放超过数字类型长度的数,然后将字符数组的值转入数字数组内进行计算。

该算法的核心就是利用两个循环依次循环处理各位数,然后判断是否需要进位。

  1. # include <stdio.h>
  2. # include <string.h> // 调用strlen函数的头文件
  3. #pragma warning(disable:4996)
  4. int main(void) {
  5. char a1[250], b1[250]; // 先定义两个字符数组,用于存储两个较多位数的乘数
  6. int a[250], b[250], c[500] = { 0 }; // 再定义三个数组,前两个用于存放字符数组里的数字各个位的数值,最后一个用于存储最终结果的各个位的数值
  7. int len1, len2, len; // 前两个分别表示字符数组a1,b1的实际长度,最后一个表示两个字符数组实际长度之和
  8. scanf("%s%s", a1, b1); // 对两个字符数组进行赋值
  9. len1 = strlen(a1); // 将字符串a1的长度赋给len1,用于数组的赋值
  10. len2 = strlen(b1); // 将字符串b1的长度赋给len2, 用于数组的赋值
  11. len = len1 + len2; // 将两字符串实际长度之和赋给len
  12. for (int i = 0; i < len1; i++) // 用for循环,实现字符数组a1内数字向数组转移
  13. a[i] = a1[len1 - 1 - i] - '0';//由于乘法是从个位数依次处理至高位,所以讲数字倒序
  14. /* 不过,字符数组内的数字与数组内数字顺序相反,这与乘法原理有关,根据ASCII,字符数组内的数字要转化成实际的数字,就要减去48,因为‘0’的ASCII码恰好是48,所以将字符数组元素-‘0’以实现转化 */
  15. for (int j = 0; j < len2; j++) // 用for循环,实现字符数组b1内数字向数组转移
  16. b[j] = b1[len1 - 1 - j] - '0';
  17. for (int i = 0; i < len1; i++) // 接下来这两个嵌套的for循环便是高精度乘法的核心
  18. for (int j = 0; j < len2; j++) { // 此处这短短三步需要结合乘法原理理解,用文字很难表达
  19. c[i + j] += a[i] * b[j]; // 数字的其中一位与另一数字其中一位相乘,先不考虑进位情况
  20. c[i + j + 1] += (c[i + j]) / 10; // 除以10的作用便是判断进多少(注意是c[i+j])
  21. c[i + j] = c[i + j] % 10; // 进位结束以后该数位便只去各位,故将其取余取余数(注意是c[i+j])
  22. } // 此处第一、第二个式子用+=,原因可根据乘法原理解释,第三个式子无需+=,原因是取该位数总值的个位即可
  23. if (c[len - 1] == 0) // 此处是判断输出的第一个数位是否为0,若为0,忽略该位数,即总长减去1
  24. len--;
  25. for (int i = len - 1; i >= 0; i--) // 倒着输出数组内的数字,得到最终结果
  26. printf("%d", c[i]);
  27. return 0;
  28. }

下面是一个高精度的例子

乐乐是一个聪明而又勤奋好学的孩子。他总喜欢探求事物的规律。一天,他突然对数的正整数次幂产生了兴趣。

众所周知,2的正整数次幂最后一位数总是不断的在重复2,4,8,6,2,4,8,6……我们说2的正整数次幂最后一位的循环长度是4(实际上4的倍数都可以说是循环长度,但我们只考虑最小的循环长度)。类似的,其余的数字的正整数次幂最后一位数也有类似的循环现象:


循环
循环长度

2
2、4、8、6
4

3
3、9、7、1
4

4
4、6
2

5
5
1

6
6
1

7
7、9、3、1
4

8
8、4、2、6
4

9
9、1
2


这时乐乐的问题就出来了:是不是只有最后一位才有这样的循环呢?对于一个整数n的正整数次幂来说,它的后k位是否会发生循环?如果循环的话,循环长度是多少呢?

注意:

1. 如果n的某个正整数次幂的位数不足k,那么不足的高位看做是0。

2. 如果循环长度是L,那么说明对于任意的正整数a,n的a次幂和a + L次幂的最后k位都相同。

Input

输入只有一行,包含两个整数n(1 <= n < 10^100)和k(1 <= k <= 100),n和k之间用一个空格隔开,表示要求n的正整数次幂的最后k位的循环长度。

Output

输出包括一行,这一行只包含一个整数,表示循环长度。如果循环不存在,输出-1。

Sample Input

32 2

Sample Output

4

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<string>
  5. #include<algorithm>
  6. using namespace std;
  7. string s;
  8. int m, k; int i, j; int a[205], aans[205], n[205], ans[205], last[205], now[205], t[205];
  9. int single_j[12] = { 1,1,4,4,2,1,1,4,4,2 };//单循环结
  10. void init() {
  11. memset(a, 0, sizeof a); memset(last, 0, sizeof last);
  12. memset(aans, 0, sizeof aans); memset(now, 0, sizeof now);
  13. memset(ans, 0, sizeof ans); memset(n, 0, sizeof n); memset(t, 0, sizeof t);
  14. //for (int i = 1;; i++) { if (m == 0) break; n[i] = m % 10; m /= 10; }//将m存入数组n,以便于高精度
  15. }
  16. void multiplyh(int x[], int y[], int z[]) {//高精度高乘
  17. for (int i = 1; i <= k; i++) {
  18. for (j = 1; j <= k; j++) {
  19. z[i + j-1]+= x[i] * y[j];
  20. z[i + j ] += (z[i + j-1] / 10);
  21. z[i + j-1] = z[i + j-1] % 10;
  22. }
  23. }
  24. }
  25. void multiplyl(int x[], int yy, int z[]) {//高精度低乘
  26. int up = 0;
  27. for (int ii = 1; ii <= k; ii++) {
  28. z[ii] = (x[ii] * yy + up) % 10;
  29. up = (x[ii] * yy + up) / 10;
  30. }
  31. }
  32. int main()
  33. {
  34. //scanf("%d%d", &m, &k);
  35. init();
  36. cin >> s;
  37. cin >> k;
  38. int temp = 0, len = s.size();
  39. for (i = len - 1; i >= len - k; i--)
  40. n[++temp] = s[i] - '0';
  41. int tmp = 0;
  42. for (int i = 1; i <= k; i++) ans[i] = n[i];
  43. for (int i = 1; i < single_j[n[1]]; i++) {
  44. memset(aans, 0, sizeof(aans));
  45. multiplyh(ans, n, aans);
  46. for (int j = 1; j <= k; j++) { ans[j] = aans[j];}//更新为第一次出现末尾循环节的状态
  47. }
  48. t[1] = single_j[n[1]];//最低位的循环结
  49. for (int i = 1; i <= k; i++) now[i] = ans[i];
  50. int pos = 2;//当前倒数位数
  51. while (pos <= k) {
  52. for (int j = 1; j <= k; j++) {
  53. ans[j] = n[j];
  54. last[j] = now[j];
  55. }
  56. tmp = 0;
  57. while (tmp < 11) {
  58. tmp++;
  59. memset(aans, 0, sizeof aans);
  60. multiplyh(ans, now, aans);
  61. for (j = 1; j <= k; j++) {
  62. ans[j] = aans[j];
  63. }
  64. if (ans[pos] == n[pos]) break;//找到循环结
  65. memset(aans, 0, sizeof(aans));
  66. multiplyh(last, now, aans);//更新last
  67. for (j = 1; j <= k; j++) last[j] = aans[j];
  68. }
  69. if (tmp >= 11) { cout << -1; return 0; }
  70. for (int j = 1; j <= k; j++) now[j] = last[j];
  71. memset(aans, 0, sizeof aans);
  72. multiplyl(t, tmp, aans);//更新循环节数组
  73. for (int i = 1; i <= 100; i++) t[i] = aans[i];
  74. pos++;
  75. }
  76. int flag = 0;//不输出前导0
  77. for (int i = 100; i >= 1; i--) {
  78. if (t[i]) flag = 1;
  79. if (flag) cout << t[i];
  80. }
  81. //cout << endl;
  82. return 0;
  83. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/546073
推荐阅读
相关标签
  

闽ICP备14008679号