高精度乘法,会比高精加法、减法稍微难那么一点点,主要是乘法要用到,高精度加法去做,也就是说,如果高精度加法没有学好,高精度乘法也就会有点难理解了,但是吧,你既然点到了这里,就说明你已经会高精度加法了,既然你已经会高精度加法了,就说明你知道为什么要用高精度了,就不再多说废话了。

c/c++最大也就是unsigned long long也就才(1019+8×1018)(10^{19}+8\times 10^{18})

如果要几百位的相乘除就不行了,所以就要用高精度了,但高精度是什么呢,一句话,就是处理很大的数相加减之类就比如几百位的数乘,就是很大的数。

高精度——单精度

高精度乘法,也就是竖……………………等会儿等会儿!

先考虑一个简单的情况:乘数中的一个是普通的 int 类型。有没有简单的处理方法呢? 一个直观的思路是直接将a每一位上的数字乘以b。从数值上来说,这个方法是正确的,但它并不符合十进制表示法,因此需要将它重新整理成正常的样子。 重整的方式,也是从个位开始逐位向上处理进位。但是这里的进位可能非常大,甚至远大于 9,因为每一位被乘上之后都可能达到 9b 的数量级。所以这里的进位不能再简单地进行 -10 运算,而是要通过除以 10 的商以及余数计算。详见代码注释,也可以参考下图展示的一个计算高精度数 1337 乘以单精度数 42 的过程。 文字描述

当然,也是出于这个原因,这个方法需要特别关注乘数aa的范围。若它和10910^9(或相应整型的取值上界)属于同一数量级,那么需要慎用高精度—单精度乘法。

最终算法:

(算法不懂的请看注释)

void mul_short(int a[], int b, int c[]) {
  clear(c);

  for (int i = 0; i < LEN - 1; ++i) {
    // 直接把 a 的第 i 位数码乘以乘数,加入结果
    c[i] += a[i] * b;

    if (c[i] >= 10) {
      // 处理进位
      // c[i] / 10 即除法的商数成为进位的增量值
      c[i + 1] += c[i] / 10;
      // 而 c[i] % 10 即除法的余数成为在当前位留下的值
      c[i] %= 10;
    }
  }
}

高精度——高精度

如果两个乘数都是高精度,那么竖式乘法又可以大显身手了。

回想竖式乘法的每一步,实际上是计算了若干a×bi×10i a \times b_i \times 10^i 的和。例如计算 1337×421337 \times 42,计算的就是 $1337 \times 2 \times 10^0 + 1337 \times 4 \times 10^1$。 于是可以将b分解为它的所有数码,其中每个数码都是单精度数,将它们分别与a相乘,再向左移动到各自的位置上相加即得答案。当然,最后也需要用与上例相同的方式处理进位。 文字描述

注意这个过程与竖式乘法不尽相同,我们的算法在每一步乘的过程中并不进位,而是将所有的结果保留在对应的位置上,到最后再统一处理进位,但这不会影响结果。

最终算法:

(算法不懂的请看注释)

void mul(int a[], int b[], int c[]) {
  clear(c);

  for (int i = 0; i < LEN - 1; ++i) {
    // 这里直接计算结果中的从低到高第 i 位,且一并处理了进位
    // 第 i 次循环为 c[i] 加上了所有满足 p + q = i 的 a[p] 与 b[q] 的乘积之和
    // 这样做的效果和直接进行上图的运算最后求和是一样的,只是更加简短的一种实现方式
    for (int j = 0; j <= i; ++j) c[i] += a[j] * b[i - j];

    if (c[i] >= 10) {
      c[i + 1] += c[i] / 10;
      c[i] %= 10;
    }
  }
}

算法都教了,怎能不上食用方法呢?

食用方法:

#include<iostream>
#include<string>
using namespace std;
const int N = 100000000;
int a[N], b[N], c[N];
int main()
{
    string str1;
    string str2;
    //以上是定义
    cin >> str1 >> str2;//输入
    for (int i = 0; i < str1.size(); i ++)//输入
        a[str1.size()-1-i] = str1[i] - '0';
    for (int i = 0; i < str2.size(); i ++)//输入
        b[str2.size()-1-i] = str2[i] - '0';
    for (int i = 0; i < str1.size(); i ++){   //最终算法的运算
        for (int j = 0; j < str2.size(); j ++){
            c[j+i] += a[i] * b[j];
            c[j+1+i] += c[j+i] / 10;
            c[j+i] %= 10;
        }
    }int as = str1.size() + str2.size();
    while (c[as-1] == 0 && as > 1)//下面是输出
        as -= 1;
    for (int i = 0; i < as; i ++)
        cout << c[as-1-i];
    return 0;
}

0 条评论

目前还没有评论...