0

I am trying to create a function that gives me the fibonacci sequence for any value of n. However, after the n = 92, I am getting incorrect answers.

eg. For n = 93
Expected output = 12200160415121876738
Actual Output = -6246583658587674878

My code is below:

import numpy as np
def Power(M, n):
         if not n:
                 return 1
         elif n % 2:
                 return M*Power(M, n-1)
         else:
                 sqrt = Power(M, n//2)
                 return sqrt**2

  def _fib(n):
     G = np.matrix([[1,1],[1,0]])
     F = Power(G, n)
     return F[0,1]   

I think it has something to do with integer overflow related to the limitation of the matrix library. I am not sure how to fix it. Please help me out. I would prefer if this algorithm is improved upon.

Algorithm used: enter image description here

Alex Ham
  • 151
  • 1
  • 12

3 Answers3

3

You should set an explicit dtype to allow for larger numbers in your matrix:

G = np.matrix([[1,1],[1,0]], dtype=np.uint64)

However, this raises the bar only slightly (if your system is not even using this as a default) and will soon overflow, too, and you won't even notice it as easily as the numbers will not get negative...

@Michael's answer works much better.

tobias_k
  • 81,265
  • 12
  • 120
  • 179
2

Sounds like you're bumping into floating point precision issues.

Python 3's integers are arbitrary precision, so you can just use them and lru_cache for memoization:

from functools import lru_cache


@lru_cache()
def fib(n):
    if n <= 1:
        return 1
    return fib(n - 2) + fib(n - 1)


for x in range(1, 95):
    print(x, fib(x - 1))

outputs

1 1
2 1
3 2
4 3
5 5
6 8
7 13
8 21
9 34
10 55
11 89
12 144
13 233
14 377
15 610
16 987
...
92 7540113804746346429
93 12200160415121876738
94 19740274219868223167
AKX
  • 152,115
  • 15
  • 115
  • 172
  • I would prefer if my current algorithm is fixed upon - I have added it in the edit. – Alex Ham Mar 04 '19 at 09:07
  • 2
    The OP algorithm takes O(log N) of basic operations and uses O(1) objects, while memoization is O(N) of basic operations and uses O(N) objects for the first call to fib(N). Actually, since these are big-int the complexity is O((log N)**2) vs. O(N log N). – Michael Veksler Mar 04 '19 at 09:34
2

You should allow big-int numbers, otherwise you are limited with the default 63 bits (+sign bit) or with np.uint64 which is only 1 bit larger:

import numpy as np
def Power(M, n):
   if not n:
      # Original 'return 1' does not work with n=0
      return np.identity(2, dtype=object)
   elif n % 2:
      return M*Power(M, n-1)
   else:
      sqrt = Power(M, n//2)
      return sqrt**2

def fib(n):
     # This allows for big-int
     G = np.matrix([[1,1],[1,0]], dtype=object)
     F = Power(G, n)
     return F[0,1]
Michael Veksler
  • 8,217
  • 1
  • 20
  • 33