0

I'm practicing using Binet formula to compute Fibonacci number, by following the Binet formula, I came up with the following code and passed the test case in leetcode:

class Solution(object):
    def fib(self, N):
        goldenratio = (1 + 5 ** 0.5) / 2
        ratio2 = (1 - 5 ** 0.5) / 2
        return int((goldenratio**N-ratio2**N)/(5**0.5))

But I don't understand the solution given by leetcode (gives correct results of course):

class Solution:
  def fib(self, N):
    golden_ratio = (1 + 5 ** 0.5) / 2
    return int((golden_ratio ** N + 1) / 5 ** 0.5)

My question about leetcode solution is: why do they plus 1 after "golden_ratio ** N"? According to Binet formula, I think my code is correct, but I want to know why leetcode uses another way but still get correct results.

Here is the link for Binet formula: https://artofproblemsolving.com/wiki/index.php/Binet%27s_Formula

M00000001
  • 309
  • 2
  • 10
  • 1
    Really this is more of a question about maths. The term in (-phi)^-1 =~ -0.6 gets small very quickly, so basically it's ok to just round the bigger term. See the "Computation by rounding" section in https://en.wikipedia.org/wiki/Fibonacci_number – Izaak van Dongen Nov 15 '19 at 22:52
  • 2
    A nitpick I have with both solutions is that they'll start producing incorrect values quite quickly, as floats only have so many significant figures of precision and F_n grows roughly exponentially. Your code gives fib(72) = 498454011879265, whereas it should be 498454011879264. You may find it interesting to think of ways to compute F_n in log(n) multiplications without loss of precision. – Izaak van Dongen Nov 15 '19 at 22:58
  • 1
    It's even worse than I thought! Upon trying to compute `fib(fib(20))` your code gives an *error*, even though the answer only has about 1000 * sqrt(2) digits! – Izaak van Dongen Nov 15 '19 at 23:20

1 Answers1

2

Your code is a digital rendering of the exact formula: φ^n - ψ^n; this is correct to the precision limits of your mechanical representation, but fails as the result grows beyond that point.

The given solution is a reasonable attempt to correct that fault: instead of subtracting a precise correction amount, since that amount is trivially shown to be less than 1, the given solution merely adds 1 and truncates to the floor integer, yielding the correct result further out than your "exact" implementation.

Try generating some results:

def fib_exact(n):
    goldenratio = (1 + 5 ** 0.5) / 2 
    ratio2 = (1 - 5 ** 0.5) / 2 
    return int((goldenratio**n - ratio2**n)/(5**0.5))

def fib_trunc(n):
    golden_ratio = (1 + 5 ** 0.5) / 2
    return int((golden_ratio ** n + 1) / 5 ** 0.5)

for n in range(100):
    a = fib_trunc(n)
    b = fib_exact(n)
    print(n, a-b, a, b)
Prune
  • 76,765
  • 14
  • 60
  • 81