二进制GCD - 算法太慢

Mat*_*ski 0 c++ algorithm bignum greatest-common-divisor

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

我的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;
}
Run Code Online (Sandbox Code Playgroud)

我也在使用自己的bitset减法功能:

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];
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

rob*_*off 6

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

真正的bignum库不使用2的基数.它们使用更大的基数,因为CPU具有一次操作多个位的指令.通常,如果您的目标是最大速度和最小尺寸,或者基数为100(使用一个字节),您将使用256(2 8),65536(2 16),4294967296(2 32)或18446744073709551616(2 64)的基数如果必须存储精确的小数部分,则每个数字),10000(每个数字两个字节),1000000000(每个数字四个字节)或10000000000000000000(每个数字八个字节).

你需要使用类似vector<uint32_t>vector<uint64_t>作为你的bignum的东西,并且一次操作32或64位,而不是一次只操作1位.

  • 是的,因为那样你就可以一次操作32位. (2认同)