这是一个数学问题,不是编程就是有用的东西!
我想计算非常大数的阶乘(10 ^ n,其中n> 6)。 我达到了任意精度,这对1000之类的任务非常有用。但它显然死了(StackOverflowException :))更高的值。我不是在寻找直接的答案,而是一些关于如何进一步发展的线索。
static BigInteger factorial(BigInteger i)
{
if (i < 1)
return 1;
else
return i * factorial(i - 1);
}
static void Main(string[] args)
{
long z = (long)Math.Pow(10, 12);
Console.WriteLine(factorial(z));
Console.Read();
}
我是否必须从System.Numerics.BigInteger辞职?我想到了一些在文件中存储必要数据的方法,因为RAM显然会耗尽。此时优化非常重要。那么你会推荐什么?
另外,我需要尽可能精确的数值。忘记提到我不需要所有这些数字,只有大约20个。
答案 0 :(得分:7)
正如其他答案所示,递归很容易被删除。现在的问题是:您可以将结果存储在BigInteger
中,还是必须转到某种外部存储?
您需要存储的位数n!
大致与n log n
成比例。 (这是 Stirling的近似的弱形式。)所以让我们看看一些大小:(注意我在这篇文章的早期版本中做了一些算术错误,我在这里进行了修改。)
(10^6)! takes order of 2 x 10^6 bytes = a few megabytes
(10^12)! takes order of 3 x 10^12 bytes = a few terabytes
(10^21)! takes order of 10^22 bytes = ten billion terabytes
一些megs将适合记忆。您可以轻松掌握几TB,但您可能需要编写一个内存管理器。 100亿太字节将占用全球所有科技公司的综合资源,但它是可行的。
现在考虑计算时间。假设我们每台机器每秒可以执行一百万次乘法,并且我们可以将工作以某种方式并行化到多台机器上。
(10^6)! takes order of one second on one machine
(10^12)! takes order of 10^6 seconds on one machine =
10 days on one machine =
a few minutes on a thousand machines.
(10^21)! takes order of 10^15 seconds on one machine =
30 million years on one machine =
3 years on 10 million machines
1 day on 10 billion machines (each with a TB drive.)
所以(10 ^ 6)!在你的掌握之中。 (10 ^ 12)!你将不得不编写自己的内存管理器和数学库,这需要一些时间来得到答案。 (10 ^ 21)!你将需要组织世界上所有的资源来解决这个问题,但它是可行的。
或者你可以找到另一种方法。
答案 1 :(得分:4)
解决方案很简单:在不使用递归的情况下计算阶乘,并且不会炸掉堆栈。
即。您没有收到此错误,因为数字太大,但是因为您有太多级别的函数调用。幸运的是,对于阶乘,没有理由以递归方式计算它们。
一旦解决了堆栈问题,您就可以担心数字格式是否可以处理“非常大”的因子。由于您不需要确切的值,因此请使用许多有效的数值近似值之一(您可以依靠它来获得所有最重要的数字)。最常见的是斯特林的近似值:
n! ~ n^n e^{-n} sqrt(2 \pi n)
图像来自this page,,您可以在那里找到讨论,第二个更准确的公式(尽管“在大多数情况下,差异非常小”,他们说)。当然这个数字对于你来说仍然太大而无法存储,但现在你可以使用对数并在提取数字之前删除不重要的数字。或者使用近似值的Wikipedia version,它已经表示为对数。
答案 2 :(得分:1)
展开递归:
static BigInteger factorial(BigInteger n)
{
BigInteger res = 1;
for (BigInteger i = 2; i <= n; ++i)
res *= i;
return res;
}