Java 使用BigInteger的斐波那契序列不会产生答案

Java 使用BigInteger的斐波那契序列不会产生答案,java,recursion,fibonacci,Java,Recursion,Fibonacci,我要找到斐波那契序列的第100个元素,我最初尝试使用int存储数字的值,但它溢出并切换为负值,就像long一样然后我遇到了biginger我确实使用了一个简单的for循环和一个数组来存储结果,然后访问前面的元素。现在,当我尝试使用递归来解决同样的问题时,程序似乎没有终止。我是不是遗漏了什么?或者不建议将biginger与递归一起使用吗?以下是代码: 在评论中,您提到您假设程序不会终止是基于它运行了5分钟以上的事实。这不是你证明不终止的方式 如果您观察到程序在一定时间内终止,那么您可以得出结论,它

我要找到斐波那契序列的第100个元素,我最初尝试使用
int
存储数字的值,但它溢出并切换为负值,就像
long
一样
然后我遇到了
biginger
我确实使用了一个简单的
for
循环和一个
数组来存储结果,然后访问前面的元素。
现在,当我尝试使用
递归来解决同样的问题时,程序似乎没有终止。我是不是遗漏了什么?或者不建议将
biginger
与递归一起使用吗?

以下是代码:


在评论中,您提到您假设程序不会终止是基于它运行了5分钟以上的事实。这不是你证明不终止的方式

如果您观察到程序在一定时间内终止,那么您可以得出结论,它确实终止了。然而,如果你没有观察到它在一定时间内终止,那么你就不能确切地说它是否终止。如果你再等一点时间,它可能会终止,如果你再等一点时间,它可能会终止,甚至理论上它可能会终止,但时间比宇宙的热死还要长

在您的特定情况下,算法是完全正确的,并且总是终止。这根本不是一个非常有效的算法:对于计算
fib(n)
fib
被称为fib(n)次,因为你一遍又一遍地计算相同的数字

如果我们假设每个时钟周期可以执行一次
fib
(这是一个乐观的假设,因为对
fib
的一次调用在大多数情况下执行一个条件、两次减法、一次加法和两次调用
fib
,并且一次加法可能已经需要多个时钟周期,具体取决于CPU),我们进一步假设你有一个100核的CPU,你的代码实际上是并行执行的,你有100个CPU,每个CPU的时钟是100 如果你有一个100台计算机的集群,那么它仍然需要你大约一个小时

在一些更现实的假设下,完成程序所需的时间更多的是几万年

由于您的代码没有并行化,为了让您的代码在5分钟内以更现实的4 GHz CPU,它需要执行
fib
几乎每时钟周期3亿次


对代码的预期性能进行一些非常粗略的估计通常会有所帮助。正如您所见,您不需要成为Java、JVM、编译器、优化、计算机组织、CPU设计或性能工程方面的专家。你不需要知道你的代码到底编译成什么。您不需要知道一个整数
ADD
需要多少时钟周期。因为即使你做了一些非常荒谬的假设,你仍然可以很容易地看到你的代码不可能在几分钟甚至几小时内完成。

一直到100只是很长的一段时间,而你的方法并不是最好的,当您多次计算大量值时,您是如何确定程序没有终止的?你调用
fib
354224848179261915075次,显然这需要一段时间。看看如何让它更快。@MrakVladar:如果我们假设
fib
只需要一个时钟周期就可以执行(这是一个非常乐观的假设,因为在核心i9上一个简单的
ADD
long
已经有十几个时钟周期)我们进一步假设你有4GHz的CPU,那么
fib(100)
大约需要2800年
import java.math.BigInteger;

class Test {
  public static void main(String[] args) {
    BigInteger n = BigInteger.valueOf(100);
    System.out.println(fib(n));
  }

  public static BigInteger fib(BigInteger n) {
    if (n.compareTo(BigInteger.valueOf(1)) == 0 || n.compareTo(BigInteger.valueOf(1)) == -1)
      return n;
    return fib(n.subtract(BigInteger.valueOf(1))).add(fib(n.subtract(BigInteger.valueOf(2))));
  }
}