根据维基百科(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;
}
我也在使用自己的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];
}
}
}
}
我没有看到任何提高此算法速度的地方(二进制GCD本身很快),但我得到的反馈是我的程序太慢了。
答案 0 :(得分:6)
您已将bignum表示为基数为2(二进制)数字的数组。
Real bignum库不使用2的基数。它们使用更大的基数,因为CPU具有一次操作多个位的指令。通常你会使用256(2 8 ),65536(2 16 ),4294967296(2 32 )或18446744073709551616(2)的基数 64 )如果你的目标是最大速度和最小尺寸,或者基数为100(每个数字一个字节),10000(每个数字有两个字节),1000000000(每个数字有4个字节),如果必须存储精确的小数部分,则为10000000000000000000(每位数为8个字节)。
您需要使用vector<uint32_t>
或vector<uint64_t>
之类的内容作为您的bignum,并且一次只能使用32位或64位,而不是一次只能使用1位。