二进制 GCD - 算法太慢

Binary GCD - too slow algorithm

本文关键字:算法 GCD 二进制      更新时间:2023-10-16

根据维基百科(http://en.wikipedia.org/wiki/Binary_GCD_algorithm),我试图为bignums(最多5000位数字)编写二进制GCD。

我的 GCD 本身如下所示:

bitset<N> gcd(bitset<N> u, bitset<N> v) {
    bitset<N> one (string("1"));
    bitset<N> zero (string("0"));
    int shift;
    if (u == 0) return v;
    if (v == 0) return u;
    for (shift = 0; ((u | v) & one) == zero; ++shift) {
        u >>= 1;
        v >>= 1;
    }
    while ((u & one) == zero) u >>= 1;
    do {
        while ((v & one) == zero) v >>= 1;
        if (u.to_string() > v.to_string()) {
            bitset<N> t = v;
            v = u;
            u = t;
        }
        bitsetSubtract(v,u);
    } while (v != 0);
    return u << shift;
}

我还使用自己的位集减法函数:

void bitsetSubtract(bitset<N> &x, const bitset<N> &y) {
    bool borrow = false;
    for (int i = 0; i < N; i++) {
        if (borrow) {
            if (x[i]) {
                x[i] = y[i];
                borrow = y[i];
            } else {
                x[i] = !y[i];
                borrow = true;
            }
        } else {
            if (x[i]) {
                x[i] = !y[i];
                borrow = false;
            } else {
                x[i] = y[i];
                borrow = y[i];
            }
        }
    }
}

我没有看到任何可以提高这种算法速度的地方(二进制 GCD 本身就很快),但我得到的反馈是我的程序太慢了。

您已将 bignum 表示为以 2 为基数(二进制)数字的数组。

真正的 bignum 库不使用 2 的基数。 它们使用更大的基数,因为 CPU 具有一次在多个位上运行的指令。 通常,如果您的目标是最大速度和最小大小,则使用基数为 256 (28)、65536 (216)、4294967296 (232) 或 18446744073709551616 (264),如果必须存储精确的小数部分,则使用基数为 100(

每个数字一个字节)、10000(每个数字两个字节)、100000000(每个数字四个字节)或 1000000000000000000(每个数字 8 个字节)。

您需要使用 vector<uint32_t>vector<uint64_t> 之类的东西作为 bignum,并且一次操作 32 或 64 位,而不是一次只处理 1 位。