具有Binets公式的第N个斐波那契在70后不准确

时间:2017-01-30 14:28:02

标签: java algorithm fibonacci

尝试使用Binets公式实现nth fibonacci,但由于某种原因binet版本统计数据偏离了第70个斐波那契数字后的实际递归版本。

这是代码

public class NthFib {

   public static void main(String[] args) {
      for (int i = 0; i < 100; i++) {
         String s1 = toUnsignedString(fib(i));
         String s2 = toUnsignedString(fibGoldenRatio(i));
         System.out.println(i + " : " + s1 + " | " + s2 + (s1.equals(s2)?" ":" not the same"));
      }

   }

   static final Map<Integer, Long> cache = new HashMap<>();

   private static long fib(int n) {

      if (n < 0) {
         return -1;
      }

      if (n == 0) {
         return 0;
      }

      if (n == 1) {
         return 1;
      }

      return cache.computeIfAbsent(n, k -> fib(k - 1) + fib(k - 2));
   }

   static final double GR = (1 + Math.sqrt(5)) / 2;
   static final double NGR = -GR + 1;

   // Binet algorithm
   private static long fibGoldenRatio(int n) {

      if (n < 0) {
         return -1;
      }

      return round(1 / sqrt(5) * (pow(GR, n) - pow(NGR, n)));
   }
}

输出如下

0 : 0 | 0 
1 : 1 | 1 
2 : 1 | 1 
3 : 2 | 2 
4 : 3 | 3 
5 : 5 | 5 
6 : 8 | 8 
7 : 13 | 13 
8 : 21 | 21 
9 : 34 | 34 
10 : 55 | 55 
11 : 89 | 89 
12 : 144 | 144 
13 : 233 | 233 
14 : 377 | 377 
15 : 610 | 610 
16 : 987 | 987 
17 : 1597 | 1597 
18 : 2584 | 2584 
19 : 4181 | 4181 
20 : 6765 | 6765 
21 : 10946 | 10946 
22 : 17711 | 17711 
23 : 28657 | 28657 
24 : 46368 | 46368 
25 : 75025 | 75025 
26 : 121393 | 121393 
27 : 196418 | 196418 
28 : 317811 | 317811 
29 : 514229 | 514229 
30 : 832040 | 832040 
31 : 1346269 | 1346269 
32 : 2178309 | 2178309 
33 : 3524578 | 3524578 
34 : 5702887 | 5702887 
35 : 9227465 | 9227465 
36 : 14930352 | 14930352 
37 : 24157817 | 24157817 
38 : 39088169 | 39088169 
39 : 63245986 | 63245986 
40 : 102334155 | 102334155 
41 : 165580141 | 165580141 
42 : 267914296 | 267914296 
43 : 433494437 | 433494437 
44 : 701408733 | 701408733 
45 : 1134903170 | 1134903170 
46 : 1836311903 | 1836311903 
47 : 2971215073 | 2971215073 
48 : 4807526976 | 4807526976 
49 : 7778742049 | 7778742049 
50 : 12586269025 | 12586269025 
51 : 20365011074 | 20365011074 
52 : 32951280099 | 32951280099 
53 : 53316291173 | 53316291173 
54 : 86267571272 | 86267571272 
55 : 139583862445 | 139583862445 
56 : 225851433717 | 225851433717 
57 : 365435296162 | 365435296162 
58 : 591286729879 | 591286729879 
59 : 956722026041 | 956722026041 
60 : 1548008755920 | 1548008755920 
61 : 2504730781961 | 2504730781961 
62 : 4052739537881 | 4052739537881 
63 : 6557470319842 | 6557470319842 
64 : 10610209857723 | 10610209857723 
65 : 17167680177565 | 17167680177565 
66 : 27777890035288 | 27777890035288 
67 : 44945570212853 | 44945570212853 
68 : 72723460248141 | 72723460248141 
69 : 117669030460994 | 117669030460994 
70 : 190392490709135 | 190392490709135 
71 : 308061521170129 | 308061521170130 not the same
72 : 498454011879264 | 498454011879265 not the same
73 : 806515533049393 | 806515533049395 not the same

我的猜测是,持有黄金比例的双倍具有有限的准确性,开始出现在第70个数字......这是正确的吗?或者我在这里遗漏了什么?

1 个答案:

答案 0 :(得分:2)

使用java.math.BigDecimal类来避免舍入问题:

static final BigDecimal SQRT_5 = BigDecimal.valueOf(Math.sqrt(5));
static final BigDecimal GR = (BigDecimal.ONE.add(SQRT_5).divide(BigDecimal.valueOf(2));
static final BigDecimal NGR = GR.negate().add(BigDecimal.ONE);

// Binet algorithm
private static long fibGoldenRatio(int n) {

  if (n < 0) {
     return -1;
  }

  return BigDecimal.ONE.divide(SQRT_5).multiply((GR.pow(n).substract(NGR.pow(n)))).toBigInteger().longValue();
}