【发布时间】:2015-09-29 01:10:54
【问题描述】:
我已经为我的教育目标实施了 Karatsuba 乘法算法。现在我正在寻找进一步的改进。我已经实现了某种长算法,无论我使用的整数表示的基数不超过 100,它都能很好地工作。
以 10 为基数并使用 clang++ -O3 范围内两个随机整数的乘积进行编译 [10^50000, 10^50001] 需要:
Naive algorithm took me 1967 cycles (1.967 seconds)
Karatsuba algorithm took me 400 cycles (0.4 seconds)
以及以 100 为底的相同数字:
Naive algorithm took me 409 cycles (0.409 seconds)
Karatsuba algorithm took me 140 cycles (0.14 seconds)
有没有办法改善这个结果? 现在我使用这样的函数来完成我的结果:
void finalize(vector<int>& res) {
for (int i = 0; i < res.size(); ++i) {
res[i + 1] += res[i] / base;
res[i] %= base;
}
}
正如您所见,它计算进位并将其推到下一位。如果我以>=1000 为基数,结果将溢出。
如果您在我的代码中看到,我使用 int 向量来表示长整数。根据我的基础,一个数字将分成矢量的不同部分。 现在我看到了几个选项:
- 对向量使用
long long类型,但对于大长度整数也可能会溢出 - 在长算术中实现进位表示
在我看到一些评论后,我决定扩大这个问题。假设我们要将长整数表示为整数向量。例如:
ULLONG_MAX = 18446744073709551615
对于输入,我们传递第 210 个斐波那契数 34507973060837282187130139035400899082304280,它不适合任何标准类型。如果我们用一个基数为 10000000 的 int 向量来表示它,它会是这样的:
v[0]: 2304280
v[1]: 89908
v[2]: 1390354
v[3]: 2187130
v[4]: 6083728
v[5]: 5079730
v[6]: 34
当我们做乘法时,我们可能会得到(为简单起见,让它是两个相同的数字)
(34507973060837282187130139035400899082304280)^2:
v[0] * v[0] = 5309706318400
...
v[0] * v[4] = 14018612755840
...
这只是第一行,我们必须这样做六个步骤。当然,在乘法过程中或进位计算后,某些步骤会导致溢出。
如果我遗漏了什么,请告诉我,我会更改它。 如果你想看完整版,在我的github
【问题讨论】:
-
如果您有工作代码,那么您的问题可能更适合codereview.stackexchange.com?
-
我投票决定将此问题作为离题结束,因为它属于 codereview。在那里,您需要在帖子中发布代码,而不是链接到您的 github。您只需发布相关部分。
-
如果你真的想加速,你应该使用另一种更快的算法:例如 Tom-Cook 或傅里叶变换。
-
@UmNyobe 真的很抱歉,没有注意到这一点。我会删除评论。当您看到它时将其标记为已过时。
-
@EdChum 在推荐迁移到代码审查之前请阅读此检查表meta.codereview.stackexchange.com/questions/1687/…
标签: c++ algorithm multiplication divide-and-conquer