除了正常的递归函数和循环方法之外,找到一个数的阶乘的有效方法是什么?由于普通方法产生输出的时间太长,有没有办法比递归和循环方法减少时间复杂度?如果不是为什么?
答案 0 :(得分:7)
79年以来!是1.711E98你只需要一个79个数字的列表来使用查找表。 因子列在:http://www.tsm-resources.com/alists/fact.html以整数格式列出或以http://home.ccil.org/~remlaps/javascript/jstest1.html以科学格式列出,因此它只是“剪切和粘贴”
答案 1 :(得分:2)
如果您想计算许多阶乘值,那么在您继续进行缓存值是一种选择。
如果您只计算一次factorial(n)
,那么循环可能是您获得的最佳效果。你可以通过一些循环展开来获得更多的处理器(一次计算两次或四次乘法),但它不太适用于非常大的因子,因为乘法本身就变成了一系列冗长的指令。
据我所知,没有“神奇”的数学来计算12 * 13 * 14 * 15
或类似的序列,而不是将它们相乘。
答案 2 :(得分:2)
您可以使用Stirling's approximation来评估大型因子。
答案 3 :(得分:2)
由于你的一条评论说你想要找到100000!,这个答案涵盖了很大的因素。
如果您不需要确切答案,可以使用Stirling's Approximation
如果你想要一个确切的答案,你需要使用像GMP这样的任意精度数学包 arbitrary precision math package
答案 4 :(得分:0)
不,不是真的。如果您担心运行时成本,可以使用查找表(需要使用预先计算的值)来减少运行时成本。
存储每个因子可能需要太多的内存,所以让我们存储每个k:thialial。 这将要求程序在运行时执行多达k次乘法。
假设您的运行时性能要求限制为每个阶乘1000次乘法。然后你需要预先计算和存储1000!,2000!,3000!等等,直到您想要支持的上限(可用内存将限制您)。
由于阶乘很快会变得比原生数据类型大,所以你需要一个可以处理大数的类。我假设它存在这样一个类,它被称为BigInteger
。
BigInteger preCalculatedValues[] = { new BigInteger("1"), new BigInteger("<value of 1000!>"), and so on... }
BigInteger factorial(int n) {
int pre = n/1000;
int i;
if (pre > LARGEST_VALUE_HANDLED) {
// Either throw an exception or let it take longer. I choose to let it take longer.
pre = LARGEST_VALUE_HANDLED;
}
BigInteger result = preCalculatedValues[pre];
for (i = pre * 1000 + 1; i <= n; i++) {
result.multiplyWith(i); // This operation is probably overloaded on the * operator
}
}
答案 5 :(得分:0)
计算非常大的事实的最简单方法是使用 伽玛函数。另一方面:它不会那么快 表查找(由其他人提出);如果你正在使用内置 在类型中,您需要以下表格:
for 32 bits: 12 entries
for 64 bits: 20 entries
for float: 34 entries
for double: 170 entries
(上表中可能有一个错误。我写道 用于快速计算它们的代码。)
对于double
,可能对于float
,通常的循环方法
无论如何,可能会引入太多的舍入错误。如果你
不想使用表,你有C ++ 11,
exp( lgamma( i + 1 ) )
应该做到这一点。 (如果你不这样做
拥有C ++ 11,无论如何你可能拥有lgamma
函数。它的
在C99。)
如果你正在处理某种扩展范围类型,那么你
可能必须为您的类型实施lgamma
(和exp
)。