我一直在处理一个库来处理超过8字节正常范围的数字(通常)。
我说几百到几千个数字。
现在我已经为这样的阶乘实现了一个函数:
largeNum factorial(largeNum& input) {
if (input > one) return (input * factorial(input-one));
else return one;
}
现在这给了我很好的结果。 100!花了大约5秒来计算并且已经超过150位数。结果是正确的。
虽然5秒是很长时间,但200已经花费分钟来计算。
例如,WolframAlpha可以计算出100000!在不到10秒的时间内。所以必须有更好的方法来做到这一点。我一直在寻找 https://en.wikipedia.org/wiki/Factorial用于所谓的Gamma功能,并想知道这是否会有所帮助。
答案 0 :(得分:3)
虽然在没有看到实现的情况下很难优化代码,但你可以通过将递归函数转换为迭代函数或者通过optimizing tail call帮助编译器为你完成它来获取一些周期。
largeNum factorial(largeNum& input) {
largeNum res = one;
while (input > one) {
res *= input;
input -= one;
}
return res;
}
当然,这只是同一个"中学的一个不同的实施"计算因子的方法。如果您正在寻找高级算法here is a page dedicated to comparing various "hard" implementations。
答案 1 :(得分:2)
我不同意所有这些答案,并说典型的迭代和递归因子实现对于大输入值来说是天真且昂贵的。
更好的方法是使用gamma function(或者,更好的是,伽玛函数的自然对数)。
这可行,因为gamma(n) = (n-1)!
或n! = gamma(n+1)
如果将此与memoization结合使用,您就拥有了一个适用于大型参数的高效解决方案。
伽玛的自然对数特别适合评估combinations and permutations。
答案 2 :(得分:1)
您可以使用线程来加速计算,使用unix pthread或C ++ std :: thread,它也是跨平台的。只有当数字很大时才会有性能提升,否则它不足以抵消创建线程的成本。
修改:此程序使用四个线程来计算阶乘。
运行程序8次后,平均线程因子时间为14秒,平均非线性因子时间为18秒。
示例程序:
#include <iostream>
#include <thread>
#include <chrono>
#include "BigInt.h"
void fact(int upper, int lower, BigInt& val)
{
for (auto i = upper; i >= lower; i--)
{
val = val*i;
}
}
int main()
{
std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now();
int n = 1000;
BigInt val1("1"), val2("1"), val3("1"), val4("1");
std::thread thr1(&fact, n, (3*n)/4, std::ref(val1));
std::thread thr2(&fact, ((3 * n) / 4) - 1, n/2, std::ref(val2));
std::thread thr3(&fact, (n / 2)-1, n/4, std::ref(val3));
std::thread thr4(&fact, (n/4)-1, 1, std::ref(val4));
thr1.join();
thr2.join();
thr3.join();
thr4.join();
auto ans = val1*val2*val3*val4;
std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::seconds>(t2 - t1).count();
std::cout << "threaded factorial time: " << duration << "\n";
t1 = std::chrono::high_resolution_clock::now();
BigInt ans2("1");
fact(n, 1, std::ref(ans2));
t2 = std::chrono::high_resolution_clock::now();
duration = std::chrono::duration_cast<std::chrono::seconds>(t2 - t1).count();
std::cout << "non threaded factorial time: " << duration;
return 0;
}