斐波那契数列定义
指的是这样一个数列:1、1、2、3、5、8、13、21、34
从第3项开始,后一项都等于前两项之和。
最简单的算法
public static int fibonacci(int n){
int a=1;
int b=1;
for(int i=3;i<=n;i++) {
int c=b;
b=a+b;
a=c;
}
return b;
}
测试
for(int i=1;i<=10;i++) {
System.out.println(i+" : "+fibonacci(i));
}
输出:
1 : 1
2 : 1
3 : 2
4 : 3
5 : 5
6 : 8
7 : 13
8 : 21
9 : 34
10 : 55
看样子已经挺不错。
但是要求第100项呢(第46项 : 1836311903),显然不行,得整个大的。
使用BigInteger
public static BigInteger bigFibonacci(int n){
BigInteger a=BigInteger.valueOf(1);
BigInteger b=BigInteger.valueOf(1);
for(int i=3;i<=n;i++) {
BigInteger c=b;
b=a.add(b);
a=c;
}
return b;
}
for(int i=1;i<=100;i++) {
System.out.println(i+" : "+bigFibonacci(i));
}
输出:
95 : 31940434634990099905
96 : 51680708854858323072
97 : 83621143489848422977
98 : 135301852344706746049
99 : 218922995834555169026
100 : 354224848179261915075
做个时间测试
long start = System.currentTimeMillis();
for(int i=1;i<=10000;i++) {
bigFibonacci(i);
//System.out.println(i+" : "+bigFibonacci(i));
}
long end = System.currentTimeMillis();
System.out.println("end - start:" + (end - start) + "ms");
end - start:5068ms
通项公式法
public static double dFibonacci(int n){
double sqrt5=Math.sqrt(5);
double a=(1+sqrt5)/2;
double b=(1-sqrt5)/2;
return 1.0/sqrt5*(Math.pow(a, n)-Math.pow(b, n));
};
测试
for(int i=1;i<=100;i++) {
System.out.println(i+" : "+bigFibonacci(i)+" ~ "+dFibonacci(i));
}
输出
43 : 433494437 ~ 4.3349443700000066E8
44 : 701408733 ~ 7.014087330000011E8
45 : 1134903170 ~ 1.1349031700000017E9
46 : 1836311903 ~ 1.8363119030000026E9
47 : 2971215073 ~ 2.971215073000005E9
97 : 83621143489848422977 ~ 8.362114348984869E19
98 : 135301852344706746049 ~ 1.3530185234470719E20
99 : 218922995834555169026 ~ 2.189229958345559E20
100 : 354224848179261915075 ~ 3.542248481792631E20
显然误差会越来越大
换用BigDecimal
1.不能使用Math.sqrt计算根号5,精度不满足。
2.BigDecimal的除法要指定小数保留位数,否则将不断重复计算小数,直至溢出。
3.舍掉小数,转为BigInteger。
public static BigInteger BigDFibonacci(int n){
BigDecimal sqrt5=BigDecimal.valueOf(5);
sqrt5=sqrt5.sqrt(MathContext.DECIMAL128);
BigDecimal a=sqrt5.add(BigDecimal.valueOf(1));
a=a.divide(BigDecimal.valueOf(2),0,BigDecimal.ROUND_HALF_UP);
a=a.pow(n);
a=new BigDecimal(a.toBigInteger());
BigDecimal b=BigDecimal.valueOf(1).subtract(sqrt5);
b=b.divide(BigDecimal.valueOf(2),0,BigDecimal.ROUND_HALF_UP);
b=b.pow(n);
b=new BigDecimal(b.toBigInteger());
BigDecimal c=a.subtract(b);
c=c.divide(sqrt5,0,BigDecimal.ROUND_HALF_UP);
return c.toBigInteger();
}
测试
for(int i=1;i<=100;i++) {
System.out.println(i+" : "+bigFibonacci(i)+" ~ "+BigDFibonacci(i));
}
90 : 2880067194370816120 ~ 2880067194370816120
91 : 4660046610375530309 ~ 4660046610375530309
92 : 7540113804746346429 ~ 7540113804746346429
93 : 12200160415121876738 ~ 12200160415121876738
94 : 19740274219868223167 ~ 19740274219868223167
95 : 31940434634990099905 ~ 31940434634990099905
96 : 51680708854858323072 ~ 51680708854858323072
97 : 83621143489848422977 ~ 83621143489848422977
98 : 135301852344706746049 ~ 135301852344706746049
99 : 218922995834555169026 ~ 218922995834555169026
100 : 354224848179261915075 ~ 354224848179261915075