➖

高精度减法

不够减就"借位接力":借位像接力棒,传到高位再传回来

💡 打个比方

减法也是列竖式!但有个麻烦:算 1000 − 1 时,个位 0−1 不够减,得找十位借;可十位也是 0,只能再找百位借;百位还是 0……借位像接力棒,一直传到千位才借到 1。

借到之后接力棒传回来:千位 1 变 0,百位变 10、借 1 给十位变 9,十位变 10、借 1 给个位变 9,个位变 10 → 10 − 1 = 9。答案 999!

高精度减法:先比较大小保证 A ≥ B(小的换到右边,记个负号),再倒着存数组、逐位减:不够就 s += 10、借位 borrow = 1;最后去前导零。

🖼️ 大图看明白

1000 − 1:借位接力棒(橙:向上求借;蓝:向下借出) 1 0 0 0 千百十个 − 1 个位 0−1 不够,找十位借 十位也是 0,再找百位借 → 百位也是 0,找千位借 千位变 0、百位变 10;百位借 1 变 9、十位变 10;十位借 1 变 9、个位变 10 0 9 9 9 10 − 1 = 9 ✓ 答案 999 个位:0 − 1 不够减 → 向十位"求借"(接力棒出发) 十位:也是 0,自己也没得借 → 接力棒继续传向百位 百位:还是 0,再传向千位 → 千位有 1!接力棒到顶 千位 1 → 0,百位 0 → 10 → 接力棒反向传回,一路借出 百位 10 借 1 变 9,十位 0 → 10 → 十位 10 借 1 变 9,个位 0 → 10 个位终于:10 − 1 = 9 → 1000 − 1 = 999(借位接力 3 棒) 数组视角:1000 − 1(下标 0 = 个位) a: 0 0 0 1 b: 1 c: 9 9 9 0 c[3] = 0 是前导零,输出时跳过 → 999 i=0:0 − 1 = −1 不够 → 加 10 c[0] = 9,borrow = 1 i=1:0 − 0 − 1 = −1 → 加 10 c[1] = 9,borrow = 1(接力继续) i=2:c[2] = 9,borrow = 1 i=3:1 − 0 − 1 = 0 → c[3] = 0,borrow = 0 去前导零:top=3 c[3]=0 → top=2 输出 c[2..0] = 999

📏 高精度减法,只要 3 步

  1. 第 1 步:先比大小:位数不同位数多的更大;位数相同从高位逐位比。A < B 就交换并记负号。
  2. 第 2 步:倒着存数组,从 i=0 逐位减:s = a[i] − b[i] − borrow;s < 0 就 s += 10、borrow = 1(借位接力)。
  3. 第 3 步:去前导零:top 从最高位往下跳过 0(至少保留一位),再输出。
为什么必须去前导零?1000 − 1 的最高列 1−0−1 = 0,c[3] = 0。直接输出会变成 "0999",而正确答案是 "999"。加法没有这个麻烦(最高位是进位,一定不是 0)。

💻 C++ 怎么写

#include <iostream>
#include <string>
using namespace std;

int main() {
    string sa, sb;
    cin >> sa >> sb;
    // 保证 A >= B:A 更小就交换并输出负号
    if (sa.length() < sb.length() ||
        (sa.length() == sb.length() && sa < sb)) {
        cout << "-";
        swap(sa, sb);
    }
    int a[1005] = {}, b[1005] = {}, c[1005] = {};
    int la = sa.length(), lb = sb.length();
    for (int i = 0; i < la; i++)
        a[i] = sa[la - 1 - i] - '0';   // 倒着存:下标 0 = 个位
    for (int i = 0; i < lb; i++)
        b[i] = sb[lb - 1 - i] - '0';
    int borrow = 0;
    for (int i = 0; i < la; i++) {
        int s = a[i] - b[i] - borrow;
        if (s < 0) { s += 10; borrow = 1; }  // 不够减,向高位借
        else borrow = 0;
        c[i] = s;
    }
    int top = la - 1;
    while (top > 0 && c[top] == 0) top--;   // 去前导零
    for (int i = top; i >= 0; i--) cout << c[i];
    cout << "\n";
    return 0;
}
// 输入 1000 1 → 999(借位接力 3 棒)
// 输入 100 99 → 1

✋ 你来试试

题目 1:1000 − 1 的借位"接力"传了几棒?每棒发生了什么?
3 棒。个位 0−1 不够 → 找十位借(第 1 棒);十位是 0 → 找百位借(第 2 棒);百位是 0 → 找千位借到 1(第 3 棒)。然后传回来:千位变 0、百位变 10 借 1 给十位变 9、十位变 10 借 1 给个位变 9、个位变 10,10−1=9。结果 999。
题目 2:为什么减法最后要"去前导零"?举个例子。
因为最高列可能减出 0:1000 − 1 时 c[3] = 1−0−1 = 0,直接输出是 "0999",但答案应是 999。所以从最高位开始跳过所有 0(至少留一位,防止 5−5=0 被跳过变成空)。注意:加法不需要这步,因为加法的最高位是进位产生的,一定非零。
🎯 一句话记住:先比大小(A≥B)再列竖式;逐位减,不够就 s+=10 借位接力;输出前去前导零。