高精度除法是最后一个高精度运算了,也就是你学完了这一节,以后碰到了要用高精度算法的题都可以做了,好了,其他的我就不多说了。

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

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

高精度除法,也就是竖……………………呸呸呸! 就是高精除低精和高精除高精啦!

停!

网上的高精度除法都是分高精除低精和高精除高精 , 你们不想学太复杂吧。

那我教你们竖式长除法的冗余运算吧

文字描述

竖式长除法实际上可以看作一个逐次减法的过程。例如上图中商数十位的计算可以这样理解:将4545减去三次1212后变得小于1212,不能再减,故此位为33

为了减少冗余运算,我们提前得到被除数的长度 lal_a 与除数的长度 lbl_b,从下标 lalbl_a - l_b 开始,从高位到低位来计算商。这和手工计算时将第一次乘法的最高位与被除数最高位对齐的做法是一样的。

食用方法实现了一个函数 greater_eq() 用于判断被除数以下标 last_dg 为最低位,是否可以再减去除数而保持非负。此后对于商的每一位,不断调用 greater_eq(),并在成立的时候用高精度减法从余数中减去除数,也即模拟了竖式除法的过程。 (食用方法不懂的请看注释)

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

食用方法:

不能食用,有毒!!!

// 被除数 a 以下标 last_dg 为最低位,是否可以再减去除数 b 而保持非负
// len 是除数 b 的长度,避免反复计算
inline bool greater_eq(int a[], int b[], int last_dg, int len) {
  // 有可能被除数剩余的部分比除数长,这个情况下最多多出 1 位,故如此判断即可
  if (a[last_dg + len] != 0) return true;
  // 从高位到低位,逐位比较
  for (int i = len - 1; i >= 0; --i) {
    if (a[last_dg + i] > b[i]) return true;
    if (a[last_dg + i] < b[i]) return false;
  }
  // 相等的情形下也是可行的
  return true;
}

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

  int la, lb;
  for (la = LEN - 1; la > 0; --la)
    if (a[la - 1] != 0) break;
  for (lb = LEN - 1; lb > 0; --lb)
    if (b[lb - 1] != 0) break;
  if (lb == 0) {
    puts("> <");
    return;
  }  // 除数不能为零

  // c 是商
  // d 是被除数的剩余部分,算法结束后自然成为余数
  for (int i = 0; i < la; ++i) d[i] = a[i];
  for (int i = la - lb; i >= 0; --i) {
    // 计算商的第 i 位
    while (greater_eq(d, b, i, lb)) {
      // 若可以减,则减
      // 这一段是一个高精度减法
      for (int j = 0; j < lb; ++j) {
        d[i + j] -= b[j];
        if (d[i + j] < 0) {
          d[i + j + 1] -= 1;
          d[i + j] += 10;
        }
      }
      // 使商的这一位增加 1
      c[i] += 1;
      // 返回循环开头,重新检查
    }
  }
}

0 条评论

目前还没有评论...