求超大斐波那契数列,迭代法,通项公式法

斐波那契数列定义

指的是这样一个数列: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

猜你喜欢

转载自blog.csdn.net/qq_39464369/article/details/90044190