当前位置:首页C++程序设计 > 正文

数值处理算法:高精度除法

作者:野牛程序员:2023-02-25 14:23:40C++程序设计阅读 2542


  1. 高精度除法

高精度除法相对来说比较复杂,需要用到一些数学知识。在这里我们介绍一种比较简单的实现方法,即二分答案。

设被除数为 $a$,除数为 $b$,商为 $c$,余数为 $r$,则有 $a = b \\times c + r$。我们可以先将被除数和除数都转化成高精度数,然后用二分答案的方式来求解商和余数。具体来说,我们二分一个 $c$ 的值,然后计算 $a - b \\times c$ 的值,如果这个值小于 $b$,则说明 $c$ 过大,需要将上界减小;否则,说明 $c$ 过小,需要将下界增大。当上界和下界重合时,就得到了最终的商和余数。

下面是一个用 C++ 实现的高精度除法的例子:

#include <iostream>
#include <cstring>

using namespace std;

const int N = 10010;

struct BigNum {
    int len, a[N];

    void init() { // 初始化
        len = 0;
        memset(a, 0, sizeof(a));
    }

    void read() { // 读入
        init();
        string s;
        cin >> s;
        len = s.size();
        for (int i = 0; i < len; i++) {
            a[i] = s[len - i - 1] - '0';
        }
    }

    void print() { // 输出
        if (len == 0) {
            cout << 0 << endl;
            return;
        }
        for (int i = len - 1; i >= 0; i--) {
            cout << a[i];
        }
        cout << endl;
    }

    void div(BigNum &b, BigNum &c, BigNum &r) { // 除法
        int d[N], k = 0;
        r.init();
        c.init();
        for (int i = len - 1; i >= 0; i--) {
            r.a[0] = a[i];
            for (int j = r.len - 1; j >= 0; j--) {
                if (j > 0) {
                    r.a[j] = r.a[j - 1];
                } else {
                    r.a[j] = 0;
                }
            }
            r.len++;
            int l = 0, h = 9, mid;
            while (l < h) {
                mid = (l + h + 1) >> 1;
                if (b.cmp(r.mul(mid)) <= 0) {
                    l = mid;
                } else {
                    h = mid - 1;
                }
            }
            c.a[k++] = l;
            r = r.sub(b.mul(l));
        }
        c.len = k;
        while (c.len > 1 && c.a[c.len - 1] == 0) {
            c.len--;
        }
    }

    int cmp(BigNum &b) { // 比较
        if (len < b.len) {
            return -1;
        } else if (len > b.len) {
            return 1;
        } else {
            for (int i = len - 1; i >= 0; i--) {
            if (a[i] < b.a[i]) {
                return -1;
            } else if (a[i] > b.a[i]) {
                return 1;
            }
        }
        return 0;
    }
}

BigNum sub(BigNum &b) { // 减法
    BigNum c;
    c.init();
    for (int i = 0; i < len; i++) {
        c.a[i] = a[i] - b.a[i];
        if (c.a[i] < 0) {
            c.a[i] += 10;
            a[i + 1]--;
        }
    }
    c.len = len;
    while (c.len > 1 && c.a[c.len - 1] == 0) {
        c.len--;
    }
    return c;
}

BigNum mul(int b) { // 乘法
    BigNum c;
    c.init();
    int t = 0;
    for (int i = 0; i < len; i++) {
        t += a[i] * b;
        c.a[i] = t % 10;
        t /= 10;
    }
    while (t) {
        c.a[c.len++] = t % 10;
        t /= 10;
    }
    return c;
}

};
int main() {
BigNum a, b, c, r;
a.read();
b.read();
a.div(b, c, r);
c.print();
r.print();
return 0;
}


在这个实现中,我们用 `BigNum` 结构体表示高精度数,包括了初始化、读入、输出、比较、减法、乘法和除法等操作。在 `div` 函数中,我们首先将被除数的每一位依次除以除数,通过二分答案的方式来求解商和余数。具体来说,我们将余数不断左移一位,然后加上被除数的当前位,这样得到的就是当前的余数。然后,我们二分一个合适的商 $l$,计算 $b \\times l$,如果这个结果小于等于当前的余数,说明当前的商 $l$ 是可行的,否则说明当前的商 $l$ 过大,需要将上界缩小;当上下界重合时,就得到了最终的商和余数。


以上就是高精度除法的一个简单实现方法,需要注意的是,这个实现并不是最优解,时间复杂度为 $O(n \\log n)$,可以通过其他方法来优化,如牛顿迭代法等。



野牛程序员教少儿编程与信息学奥赛-微信|电话:15892516892
野牛程序员教少儿编程与信息学竞赛-微信|电话:15892516892
相关推荐

最新推荐

热门点击