private static final MathContext _mc = new MathContext(20, RoundingMode.HALF_UP);
private static final double _sqrt5 = Math.sqrt(5);
public static final BigDecimal Sqrt5 = new BigDecimal(_sqrt5, _mc);
public static final BigDecimal Phi = new BigDecimal((1 + _sqrt5)/2, _mc);
public static BigDecimal estimate(int n) {
return Phi.pow(n, _mc).divide(Sqrt5, _mc);
}
斐波那契数的定义
斐波那契数是一个自然数序列,以数字 0 和 1 开头,每个后续数字都等于前两个数字的总和:
前 10 个斐波那契数:
获得第一个
n
斐波那契数要找到第一个
n
斐波那契数,您可以创建一个大小为 的数组n
,前两个元素将是 0 和 1,其余元素可以使用循环和上述公式获得:该代码假定存在
n
可以从键盘输入的变量,如下所示:填充数组后,可以使用循环将
f
获得的第一个n
斐波那契数显示在屏幕上:在线示例代码
值得注意的是
int
,Java中的类型只允许你存储最多2 31 -1的数字,所以上面的方法只会计算前46个斐波那契数(试图计算第47个斐波那契数时,会发生溢出并且会得到一个负数)。使用数据类型long
而不是int
无溢出将计算前 91 个斐波那契数。要计算后续的斐波那契数,可以使用JavaBigInteger
中实现长算法的类。获取
n
第 斐波那契数只获取
n
第 -th 斐波那契数,不需要使用数组,创建两个变量a
和就足够了b
,它将存储最后两个斐波那契数,并重新计算这些变量的n - 2
时间:在线示例代码
斐波那契数的递归计算
还有一种计算斐波那契数的递归方法。但是,不建议使用它,因为与前两种方法不同,它在线性时间内工作
n
,递归方法可能需要更长的时间。在线示例代码
递归方法在指数时间内工作
n
,例如,n
等于 46,递归方法花费的时间超过五秒,而记住最后两个斐波那契数的方法花费不到十分之一秒)。递归方法可以工作很长时间,因为在计算过程中会从同一个参数多次调用函数(例如,计算
f(5)
函数时会递归调用f(4)
andf(3)
,两个递归调用都会转为f(2)
),这将导致重复重复相同的操作。O(log n)
使用快速矩阵乘法(使用乘法运算)快速计算斐波那契数考虑矩阵:
使用矩阵乘法,最后两个斐波那契数的递归关系可以写成:
扩大这个比率,我们得到:
因此,要找到第 th 个斐波那契数,只需将矩阵乘以1 次方
n
就足够了。这可以通过快速求幂算法来完成。A
n - 1
在线示例代码
除了@diralik的回答
无需矩阵的快速计算
矩阵幂可以用斐波那契数来表示。用归纳法很容易证明
然后
这个表达式为我们提供了将斐波那契数指数加倍的公式:
这个公式在下面的代码中实现
Fib.fast(int)
。通过黄金比例进行评估
对于斐波那契数,有比奈公式,它无需迭代即可计算斐波那契数。
由于斐波那契数很快就超出了类型
double
,为了通过比内公式估计斐波那契数,我使用BigDecimal
四舍五入到 20 位有效数字。结果,此四舍五入给出了 10 个正确数字。速度比较
计算斐波那契数的快速公式每次迭代使用三个乘法。但由于迭代次数以对数增长
n
,因此快速公式的总计算时间比经典公式少几倍。以下是 的比较结果
n=100, 1000, 10000, 100000, 1000000
。以毫秒为单位的时间。Estimate
- 这只是根据比内公式的估计。输出使用一个函数
asFloatString
,对于大整数,该函数将近似表示构建为实数