• C++
  • 高精度除法教程:用高精度减法高精度减法模拟除法(C++实现,无优化)

  • @ 2025-9-21 13:32:02

高精度除法教程:用高精度减法高精度减法模拟除法(C++实现,无优化)

在处理超出内置数据类型范围的大整数除法时,我们可以通过模拟手动计算的方式实现。本教程将介绍如何使用高精度减法来模拟除法运算,完全遵循手动计算逻辑,不做任何优化,帮助理解其核心原理。

一、基本原理

用减法模拟除法的核心思想很简单:求被除数a除以除数b的商和余数,本质上就是计算"a中包含多少个b",商就是这个数量,而剩下的部分就是余数。

例如计算10÷3:

  • 10 - 3 = 7(商+1)
  • 7 - 3 = 4(商+1)
  • 4 - 3 = 1(商+1)
  • 1 < 3,停止
  • 结果:商=3,余数=1

二、数据表示

我们使用字符串存储大整数,并用数组来处理每一位数字,约定如下:

  • 数组下标0表示最低位(个位),方便进位和借位操作
  • 例如"1234"存储为数组[4,3,2,1]

三、核心操作实现

3.1 高精度比较函数

判断两个大整数的大小,这是决定是否可以继续减法的关键:

// 比较两个大整数,a和b都是最低位在前的数组
// 返回值:1(a > b),0(a == b),-1(a < b)
int compare(const vector<int>& a, const vector<int>& b) {
    // 先比较长度,长的数更大
    if (a.size() > b.size()) return 1;
    if (a.size() < b.size()) return -1;
    
    // 长度相同则从最高位到最低位比较
    for (int i = a.size() - 1; i >= 0; i--) {
        if (a[i] > b[i]) return 1;
        if (a[i] < b[i]) return -1;
    }
    return 0; // 相等
}

3.2 高精度减法函数

实现两个大整数的减法(a - b),要求a > b:

// 高精度减法,a - b,结果存储在a中
// 要求:a > b,都是最低位在前的数组
void subtract(vector<int>& a, const vector<int>& b) {
    int borrow = 0;
    for (int i = 0; i < a.size(); i++) {
        // 当前位的值 = a的当前位 - 借位
        int val = a[i] - borrow;
        // 如果b还有这一位,则减去
        if (i < b.size()) {
            val -= b[i];
        }
        
        // 处理借位
        if (val < 0) {
            val += 10;
            borrow = 1;
        } else {
            borrow = 0;
        }
        
        a[i] = val;
    }
    
    // 移除前导零(最高位的零)
    while (a.size() > 1 && a.back() == 0) {
        a.pop_back();
    }
}

3.3 字符串转数组函数

将输入的数字字符串转换为我们约定的数组格式:

// 将数字字符串转换为最低位在前的数组
vector<int> strToVector(const string& s) {
    vector<int> res;
    for (int i = s.size() - 1; i >= 0; i--) {
        res.push_back(s[i] - '0');
    }
    return res;
}

3.4 数组转字符串函数

将计算结果的数组转换回字符串格式:

// 将最低位在前的数组转换为数字字符串
string vectorToStr(const vector<int>& v) {
    string res;
    for (int i = v.size() - 1; i >= 0; i--) {
        res += (v[i] + '0');
    }
    return res.empty() ? "0" : res;
}

四、完整除法实现

结合以上函数,实现用减法模拟的高精度除法:

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

// 比较两个大整数,a和b都是最低位在前的数组
// 返回值:1(a > b),0(a == b),-1(a < b)
int compare(const vector<int>& a, const vector<int>& b) {
    if (a.size() > b.size()) return 1;
    if (a.size() < b.size()) return -1;
    
    for (int i = a.size() - 1; i >= 0; i--) {
        if (a[i] > b[i]) return 1;
        if (a[i] < b[i]) return -1;
    }
    return 0;
}

// 高精度减法,a - b,结果存储在a中
// 要求:a > b,都是最低位在前的数组
void subtract(vector<int>& a, const vector<int>& b) {
    int borrow = 0;
    for (int i = 0; i < a.size(); i++) {
        int val = a[i] - borrow;
        if (i < b.size()) {
            val -= b[i];
        }
        
        if (val < 0) {
            val += 10;
            borrow = 1;
        } else {
            borrow = 0;
        }
        
        a[i] = val;
    }
    
    // 移除前导零
    while (a.size() > 1 && a.back() == 0) {
        a.pop_back();
    }
}

// 将数字字符串转换为最低位在前的数组
vector<int> strToVector(const string& s) {
    vector<int> res;
    for (int i = s.size() - 1; i >= 0; i--) {
        res.push_back(s[i] - '0');
    }
    return res;
}

// 将最低位在前的数组转换为数字字符串
string vectorToStr(const vector<int>& v) {
    string res;
    for (int i = v.size() - 1; i >= 0; i--) {
        res += (v[i] + '0');
    }
    return res.empty() ? "0" : res;
}

// 高精度除法:用减法模拟,返回(商, 余数)
pair<string, string> highPrecisionDivision(const string& dividend, const string& divisor) {
    // 处理除数为0的情况
    if (divisor == "0") {
        throw invalid_argument("除数不能为0");
    }
    
    // 处理被除数为0的情况
    if (dividend == "0") {
        return make_pair("0", "0");
    }
    
    vector<int> a = strToVector(dividend);
    vector<int> b = strToVector(divisor);
    
    // 如果被除数小于除数,商为0,余数为被除数
    if (compare(a, b) < 0) {
        return make_pair("0", dividend);
    }
    
    // 初始化商为0
    vector<int> quotient(1, 0);
    
    // 不断用a减b,直到a < b
    while (compare(a, b) >= 0) {
        subtract(a, b);
        
        // 商加1
        int carry = 1;
        for (int i = 0; i < quotient.size() && carry; i++) {
            int sum = quotient[i] + carry;
            quotient[i] = sum % 10;
            carry = sum / 10;
        }
        if (carry) {
            quotient.push_back(carry);
        }
    }
    
    // 转换结果为字符串
    string quotientStr = vectorToStr(quotient);
    string remainderStr = vectorToStr(a);
    
    return make_pair(quotientStr, remainderStr);
}

int main() {
    // 测试示例
    string dividend, divisor;
    
    cout << "请输入被除数: ";
    cin >> dividend;
    cout << "请输入除数: ";
    cin >> divisor;
    
    try {
        auto result = highPrecisionDivision(dividend, divisor);
        cout << dividend << " ÷ " << divisor << " = " << result.first 
             << ", 余数: " << result.second << endl;
    } catch (const invalid_argument& e) {
        cout << "错误: " << e.what() << endl;
    }
    
    // 以下是一些预设的测试用例
    cout << "\n测试用例:\n";
    auto test = [](const string& a, const string& b) {
        auto res = highPrecisionDivision(a, b);
        cout << a << " ÷ " << b << " = " << res.first << ", 余数: " << res.second << endl;
    };
    
    test("10", "3");        // 10 ÷ 3 = 3, 余数: 1
    test("100", "7");       // 100 ÷ 7 = 14, 余数: 2
    test("12345", "23");    // 12345 ÷ 23 = 536, 余数: 17
    test("99999", "123");   // 99999 ÷ 123 = 812, 余数: 33
    test("123", "456");     // 123 ÷ 456 = 0, 余数: 123
    test("0", "12345");     // 0 ÷ 12345 = 0, 余数: 0
    
    return 0;
}

五、代码解析

上述代码的核心逻辑在highPrecisionDivision函数中,其工作流程如下:

  1. 参数检查:处理除数为0和被除数为0的特殊情况
  2. 初始化:将输入的字符串转换为我们约定的数组格式
  3. 特殊情况处理:如果被除数小于除数,直接返回商0和余数为被除数
  4. 核心循环
    • 只要被除数大于等于除数,就用被除数减去除数
    • 每次减法后,商加1(注意处理商的进位)
  5. 结果转换:将表示商和余数的数组转换回字符串格式并返回

六、算法特点与性能

这种用减法模拟除法的方法:

  • 优点:逻辑简单直观,完全模拟手动计算过程,易于理解
  • 缺点:效率极低,时间复杂度为O(a/b),当商很大时(如1000000÷1)需要执行百万次减法
  • 适用场景:仅用于理解除法的基本原理,不适合实际工程中处理大整数除法

七、总结

本教程介绍了如何使用高精度减法来模拟除法运算,通过这种方法,我们可以处理任意大小的整数除法。虽然这种方法效率不高,但它清晰地展示了除法运算的本质:商是被除数中包含除数的个数,余数是除法后剩下的部分。

在实际应用中,我们通常会使用更高效的算法(如模拟竖式除法),但理解这种最基本的实现方式,有助于深入理解高精度计算的核心思想。

0 条评论

目前还没有评论...