Fast Fibonacci computation - python

I saw a comment on Google+ a few weeks ago in which someone demonstrated a straight-forward computation of Fibonacci numbers which was not based on recursion and didn't use memoization. He effectively just remembered the last 2 numbers and kept adding them. This is an O(n) algorithm, but he implemented it very cleanly. So I quickly pointed out that a quicker way is to take advantage of the fact that they can be computed as powers of [[0,1],[1,1]] matrix and it requires only a O(log(N)) computation.
The problem, of course is that this is far from optimal past a certain point. It is efficient as long as the numbers are not too large, but they grow in length at the rate of N*log(phi)/log(10), where N is the Nth Fibonacci number and phi is the golden ratio ( (1+sqrt(5))/2 ~ 1.6 ). As it turns out, log(phi)/log(10) is very close to 1/5. So Nth Fibonacci number can be expected to have roughly N/5 digits.
Matrix multiplication, heck even number multiplication, gets very slow when the numbers start to have millions or billions of digits. So the F(100,000) took about .03 seconds to compute (in Python), while F(1000,000) took roughly 5 seconds. This is hardly O(log(N)) growth. My estimate was that this method, without improvements, only optimizes the computation to be O( (log(N)) ^ (2.5) ) or so.
Computing a billionth Fibonacci number, at this rate, would be prohibitively slow (even though it would only have ~ 1,000,000,000 / 5 digits so it easily fits within 32-bit memory).
Does anyone know of an implementation or algorithm which would allow a faster computation? Perhaps something which would allow calculation of a trillionth Fibonacci number.
And just to be clear, I am not looking for an approximation. I am looking for the exact computation (to the last digit).
Edit 1: I am adding the Python code to show what I believe is O( (log N) ^ 2.5) ) algorithm.
from operator import mul as mul
from time import clock
class TwoByTwoMatrix:
__slots__ = "rows"
def __init__(self, m):
self.rows = m
def __imul__(self, other):
self.rows = [[sum(map(mul, my_row, oth_col)) for oth_col in zip(*other.rows)] for my_row in self.rows]
return self
def intpow(self, i):
i = int(i)
result = TwoByTwoMatrix([[long(1),long(0)],[long(0),long(1)]])
if i <= 0:
return result
k = 0
while i % 2 == 0:
k +=1
i >>= 1
multiplier = TwoByTwoMatrix(self.rows)
while i > 0:
if i & 1:
result *= multiplier
multiplier *= multiplier # square it
i >>= 1
for j in xrange(k):
result *= result
return result
m = TwoByTwoMatrix([[0,1],[1,1]])
t1 = clock()
print len(str(m.intpow(100000).rows[1][1]))
t2 = clock()
print t2 - t1
t1 = clock()
print len(str(m.intpow(1000000).rows[1][1]))
t2 = clock()
print t2 - t1
Edit 2:
It looks like I didn't account for the fact that len(str(...)) would make a significant contribution to the overall runtime of the test. Changing tests to
from math import log as log
t1 = clock()
print log(m.intpow(100000).rows[1][1])/log(10)
t2 = clock()
print t2 - t1
t1 = clock()
print log(m.intpow(1000000).rows[1][1])/log(10)
t2 = clock()
print t2 - t1
shortened the runtimes to .008 seconds and .31 seconds (from .03 seconds and 5 seconds when len(str(...)) were used).
Because M=[[0,1],[1,1]] raised to power N is [[F(N-2), F(N-1)], [F(N-1), F(N)]],
the other obvious source of inefficiency was calculating (0,1) and (1,0) elements of the matrix as if they were distinct. This (and I switched to Python3, but Python2.7 times are similar):
class SymTwoByTwoMatrix():
# elments (0,0), (0,1), (1,1) of a symmetric 2x2 matrix are a, b, c.
# b is also the (1,0) element because the matrix is symmetric
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
def __imul__(self, other):
# this multiplication does work correctly because we
# are multiplying powers of the same symmetric matrix
self.a, self.b, self.c = \
self.a * other.a + self.b * other.b, \
self.a * other.b + self.b * other.c, \
self.b * other.b + self.c * other.c
return self
def intpow(self, i):
i = int(i)
result = SymTwoByTwoMatrix(1, 0, 1)
if i <= 0:
return result
k = 0
while i % 2 == 0:
k +=1
i >>= 1
multiplier = SymTwoByTwoMatrix(self.a, self.b, self.c)
while i > 0:
if i & 1:
result *= multiplier
multiplier *= multiplier # square it
i >>= 1
for j in range(k):
result *= result
return result
calculated F(100,000) in .006, F(1,000,000) in .235 and F(10,000,000) in 9.51 seconds.
Which is to be expected. It is producing results 45% faster for the fastest test and it is expected that the gain should asymptotically approach
phi/(1+2*phi+phi*phi) ~ 23.6%.
The (0,0) element of M^N is actually N-2nd Fibonacci number:
for i in range(15):
x = m.intpow(i)
print([x.a,x.b,x.c])
gives
[1, 0, 1]
[0, 1, 1]
[1, 1, 2]
[1, 2, 3]
[2, 3, 5]
[3, 5, 8]
[5, 8, 13]
[8, 13, 21]
[13, 21, 34]
[21, 34, 55]
[34, 55, 89]
[55, 89, 144]
[89, 144, 233]
[144, 233, 377]
[233, 377, 610]
I would expect that not having to calculate element (0,0) would produce a speed up of additional 1/(1+phi+phi*phi) ~ 19%. But the lru_cache of F(2N) and F(2N-1) solution given by Eli Korvigo below actually gives a speed up of 4 times (ie, 75%). So, while I have not worked out a formal explanation, I am tempted to think that it caches the spans of 1's within the binary expansion of N and does the minimum number of multiplications necessary. Which obviates the need to find those ranges, precompute them and then multiply them at the right point in the expansion of N. lru_cache allows for a top-to-bottom computation of what would have been a more complicated buttom-to-top computation.
Both SymTwoByTwoMatrix and the lru_cache-of-F(2N)-and-F(2N-1) are taking roughly 40 times longer to compute every time N grows 10 times. I think that's possibly due to Python's implementation of multiplication of long ints. I think the multiplication of large numbers and their addition should be parallelizable. So a multi-threaded sub-O(N) solution should be possible even though (as Daniel Fisher states in comments) the F(N) solution is Theta(n).

Since Fibonacci sequence is a linear recurrence, its members can be evaluated in closed form. This involves computing a power, which can be done in O(logn) similarly to the matrix-multiplication solution, but the constant overhead should be lower. That's the fastest algorithm I know.
EDIT
Sorry, I missed the "exact" part. Another exact O(log(n)) alternative for the matrix-multiplication can be calculated as follows
from functools import lru_cache
#lru_cache(None)
def fib(n):
if n in (0, 1):
return 1
if n & 1: # if n is odd, it's faster than checking with modulo
return fib((n+1)//2 - 1) * (2*fib((n+1)//2) - fib((n+1)//2 - 1))
a, b = fib(n//2 - 1), fib(n//2)
return a**2 + b**2
This is based on the derivation from a note by Prof. Edsger Dijkstra. The solution exploits the fact that to calculate both F(2N) and F(2N-1) you only need to know F(N) and F(N-1). Nevertheless, you are still dealing with long-number arithmetics, though the overhead should be smaller than that of the matrix-based solution. In Python you'd better rewrite this in imperative style due to the slow memoization and recursion, though I wrote it this way for the clarity of the functional formulation.

This is too long for a comment, so I'll leave an answer.
The answer by Aaron is correct, and I've upvoted it, as should you. I will provide the same answer, and explain why it is not only correct, but the best answer posted so far. The formula we're discussing is:
Computing Φ is O(M(n)), where M(n) is the complexity of multiplication (currently a little over linearithmic) and n is the number of bits.
Then there's a power function, which can be expressed as a log (O(M(n)•log(n)), a multiply (O(M(n))), and an exp (O(M(n)•log(n)).
Then there's a square root (O(M(n))), a division (O(M(n))), and a final round (O(n)).
This makes this answer something like O(n•log^2(n)•log(log(n))) for n bits.
I haven't thoroughly analyzed the division algorithm, but if I'm reading this right, each bit might need a recursion (you need to divide the number log(2^n)=n times) and each recursion needs a multiply. Therefore it can't be better than O(M(n)•n), and that's exponentially worse.

Using the weird square rooty equation in the other answer closed form fibo you CAN compute the kth fibonacci number exactly. This is because the $\sqrt(5)$ falls out in the end. You just have to arrange your multiplication to keep track of it in the meantime.
def rootiply(a1,b1,a2,b2,c):
''' multipy a1+b1*sqrt(c) and a2+b2*sqrt(c)... return a,b'''
return a1*a2 + b1*b2*c, a1*b2 + a2*b1
def rootipower(a,b,c,n):
''' raise a + b * sqrt(c) to the nth power... returns the new a,b and c of the result in the same format'''
ar,br = 1,0
while n != 0:
if n%2:
ar,br = rootiply(ar,br,a,b,c)
a,b = rootiply(a,b,a,b,c)
n /= 2
return ar,br
def fib(k):
''' the kth fibonacci number'''
a1,b1 = rootipower(1,1,5,k)
a2,b2 = rootipower(1,-1,5,k)
a = a1-a2
b = b1-b2
a,b = rootiply(0,1,a,b,5)
# b should be 0!
assert b == 0
return a/2**k/5
if __name__ == "__main__":
assert rootipower(1,2,3,3) == (37,30) # 1+2sqrt(3) **3 => 13 + 4sqrt(3) => 39 + 30sqrt(3)
assert fib(10)==55

From Wikipedia,
For all n ≥ 0, the number Fn is the closest integer to phi^n/sqrt(5) where phi is the golden ratio. Therefore, it can be found by rounding, that is by the use of the nearest integer function

Related

Efficient algorithm for getting number of partitions of integer with distinct parts (Partition function Q)

I need to create function which will take one argument int and output int which represents the number of distinct parts of input integer's partition. Namely,
input:3 -> output: 1 -> {1, 2}
input:6 -> output: 3 -> {1, 2, 3}, {2, 4}, {1, 5}
...
Since I am looking only for distinct parts, something like this is not allowed:
4 -> {1, 1, 1, 1} or {1, 1, 2}
So far I have managed to come up with some algorithms which would find every possible combination, but they are pretty slow and effective only until n=100 or so.
And since I only need number of combinations not the combinations themselves Partition Function Q should solve the problem.
Does anybody know how to implement this efficiently?
More information about the problem: OEIS, Partition Function Q
EDIT:
To avoid any confusion, the DarrylG answer also includes the trivial (single) partition, but this does not affect the quality of it in any way.
EDIT 2:
The jodag (accepted answer) does not include trivial partition.
Tested two algorithms
Simple recurrence relation
WolframMathword algorithm (based upon Georgiadis, Kediaya, Sloane)
Both implemented with Memoization using LRUCache.
Results: WolframeMathword approach orders of magnitude faster.
1. Simple recurrence relation (with Memoization)
Reference
Code
#lru_cache(maxsize=None)
def p(n, d=0):
if n:
return sum(p(n-k, n-2*k+1) for k in range(1, n-d+1))
else:
return 1
Performance
n Time (sec)
10 time elapsed: 0.0020
50 time elapsed: 0.5530
100 time elapsed: 8.7430
200 time elapsed: 168.5830
2. WolframMathword algorithm
(based upon Georgiadis, Kediaya, Sloane)
Reference
Code
# Implementation of q recurrence
# https://mathworld.wolfram.com/PartitionFunctionQ.html
class PartitionQ():
def __init__(self, MAXN):
self.MAXN = MAXN
self.j_seq = self.calc_j_seq(MAXN)
#lru_cache
def q(self, n):
" Q strict partition function "
assert n < self.MAXN
if n == 0:
return 1
sqrt_n = int(sqrt(n)) + 1
temp = sum(((-1)**(k+1))*self.q(n-k*k) for k in range(1, sqrt_n))
return 2*temp + self.s(n)
def s(self, n):
if n in self.j_seq:
return (-1)**self.j_seq[n]
else:
return 0
def calc_j_seq(self, MAX_N):
""" Used to determine if n of form j*(3*j (+/-) 1) / 2
by creating a dictionary of n, j value pairs "
result = {}
j = 0
valn = -1
while valn <= MAX_N:
jj = 3*j*j
valp, valn = (jj - j)//2, (jj+j)//2
result[valp] = j
result[valn] = j
j += 1
return result
Performance
n Time (sec)
10 time elapsed: 0.00087
50 time elapsed: 0.00059
100 time elapsed: 0.00125
200 time elapsed: 0.10933
Conclusion: This algorithm is orders of magnitude faster than the simple recurrence relationship
Algorithm
Reference
I think a straightforward and efficient way to solve this is to explicitly compute the coefficient of the generating function from the Wolfram PartitionsQ link in the original post.
This is a pretty illustrative example of how to construct generating functions and how they can be used to count solutions. To start, we recognize that the problem may be posed as follows:
Let m_1 + m_2 + ... + m_{n-1} = n where m_j = 0 or m_j = j for all j.
Q(n) is the number of solutions of the equation.
We can find Q(n) by constructing the following polynomial (i.e. the generating function)
(1 + x)(1 + x^2)(1 + x^3)...(1 + x^(n-1))
The number of solutions is the number of ways the terms combine to make x^n, i.e. the coefficient of x^n after expanding the polynomial. Therefore, we can solve the problem by simply performing the polynomial multiplication.
def Q(n):
# Represent polynomial as a list of coefficients from x^0 to x^n.
# G_0 = 1
G = [int(g_pow == 0) for g_pow in range(n + 1)]
for k in range(1, n):
# G_k = G_{k-1} * (1 + x^k)
# This is equivalent to adding G shifted to the right by k to G
# Ignore powers greater than n since we don't need them.
G = [G[g_pow] if g_pow - k < 0 else G[g_pow] + G[g_pow - k] for g_pow in range(n + 1)]
return G[n]
Timing (average of 1000 iterations)
import time
print("n Time (sec)")
for n in [10, 50, 100, 200, 300, 500, 1000]:
t0 = time.time()
for i in range(1000):
Q(n)
elapsed = time.time() - t0
print('%-5d%.08f'%(n, elapsed / 1000))
n Time (sec)
10 0.00001000
50 0.00017500
100 0.00062900
200 0.00231200
300 0.00561900
500 0.01681900
1000 0.06701700
You can memoize the recurrences in equations 8, 9, and 10 in the mathematica article you linked for a quadratic in N runtime.
def partQ(n):
result = []
def rec(part, tgt, allowed):
if tgt == 0:
result.append(sorted(part))
elif tgt > 0:
for i in allowed:
rec(part + [i], tgt - i, allowed - set(range(1, i + 1)))
rec([], n, set(range(1, n)))
return result
The work is done by the rec internal function, which takes:
part - a list of parts whose sum is always equal to or less than the target n
tgt - the remaining partial sum that needs to be added to the sum of part to get to n
allowed - a set of number still allowed to be used in the full partitioning
When tgt = 0 is passed, that meant the sum of part if n, and the part is added to the result list. If tgt is still positive, each of the allowed numbers is attempted as an extension of part, in a recursive call.

What is the complexity of this recursive algorithm?

Does the following algorithm have a complexity of O(nlogn)?
The thing that confuses me is that this algorithm divides twice, not once as a regular O(nlogn) algorithm, and each time it does O(n) work.
def equivalent(a, b):
if isEqual(a, b):
return True
half = int(len(a) / 2)
if 2*half != len(a):
return False
if (equivalent(a[:half], b[:half]) and equivalent(a[half:], b[half:])):
return True
if (equivalent(a[:half], b[half:]) and equivalent(a[half:], b[:half])):
return True
return False
Each of the 4 recursive calls to equivalent reduces the amount of input data by a factor of 2. Thus, assuming that a and b have the same length, and isEqual has linear time complexity, we can construct the recurrence relation for the overall complexity:
Where C is some constant. We can solve this relation by repeatedly substituting and spotting a pattern:
What is the upper limit of the summation, m? The stopping condition occurs when len(a) is odd. That may be anywhere between N and 1, depending on the prime decomposition of N. In the worse case scenario, N is a power of 2, so the function recurses until len(a) = 1, i.e.
To enhance the above answer, there is a direct way to calculate with 'Master Method'. The master method works only for following type of recurrences.
T(n) = aT(n/b) + f(n) where a >= 1 and b > 1
We have three cases based on the f(n) as below and reduction for them:
If f(n) = Θ(nc) where c < Logba then T(n) = Θ(n Logba)
If f(n) = Θ(nc) where c = Logba then T(n) = Θ(nc Log n)
If f(n) = Θ(nc) where c > Logba then T(n) = Θ(f(n)) = Θ(nc)
In your case,
we have a = 4, b = 2, c = 1 and c < Logba
i.e. 1 < log24
Hence => case 1
Therefore:
T(n) = Θ(nLogba)
T(n) = Θ(nLog24)
T(n) = Θ(n2)
More details with examples can be found in wiki.
Hope it helps!

Efficient finding primitive roots modulo n using Python?

I'm using the following code for finding primitive roots modulo n in Python:
Code:
def gcd(a,b):
while b != 0:
a, b = b, a % b
return a
def primRoots(modulo):
roots = []
required_set = set(num for num in range (1, modulo) if gcd(num, modulo) == 1)
for g in range(1, modulo):
actual_set = set(pow(g, powers) % modulo for powers in range (1, modulo))
if required_set == actual_set:
roots.append(g)
return roots
if __name__ == "__main__":
p = 17
primitive_roots = primRoots(p)
print(primitive_roots)
Output:
[3, 5, 6, 7, 10, 11, 12, 14]
Code fragment extracted from: Diffie-Hellman (Github)
Can the primRoots method be simplified or optimized in terms of memory usage and performance/efficiency?
One quick change that you can make here (not efficiently optimum yet) is using list and set comprehensions:
def primRoots(modulo):
coprime_set = {num for num in range(1, modulo) if gcd(num, modulo) == 1}
return [g for g in range(1, modulo) if coprime_set == {pow(g, powers, modulo)
for powers in range(1, modulo)}]
Now, one powerful and interesting algorithmic change that you can make here is to optimize your gcd function using memoization. Or even better you can simply use built-in gcd function form math module in Python-3.5+ or fractions module in former versions:
from functools import wraps
def cache_gcd(f):
cache = {}
#wraps(f)
def wrapped(a, b):
key = (a, b)
try:
result = cache[key]
except KeyError:
result = cache[key] = f(a, b)
return result
return wrapped
#cache_gcd
def gcd(a,b):
while b != 0:
a, b = b, a % b
return a
# or just do the following (recommended)
# from math import gcd
Then:
def primRoots(modulo):
coprime_set = {num for num in range(1, modulo) if gcd(num, modulo) == 1}
return [g for g in range(1, modulo) if coprime_set == {pow(g, powers, modulo)
for powers in range(1, modulo)}]
As mentioned in comments, as a more pythoinc optimizer way you can use fractions.gcd (or for Python-3.5+ math.gcd).
Based on the comment of Pete and answer of Kasramvd, I can suggest this:
from math import gcd as bltin_gcd
def primRoots(modulo):
required_set = {num for num in range(1, modulo) if bltin_gcd(num, modulo) }
return [g for g in range(1, modulo) if required_set == {pow(g, powers, modulo)
for powers in range(1, modulo)}]
print(primRoots(17))
Output:
[3, 5, 6, 7, 10, 11, 12, 14]
Changes:
It now uses pow method's 3-rd argument for the modulo.
Switched to gcd built-in function that's defined in math (for Python 3.5) for a speed boost.
Additional info about built-in gcd is here: Co-primes checking
In the special case that p is prime, the following is a good bit faster:
import sys
# translated to Python from http://www.bluetulip.org/2014/programs/primitive.js
# (some rights may remain with the author of the above javascript code)
def isNotPrime(possible):
# We only test this here to protect people who copy and paste
# the code without reading the first sentence of the answer.
# In an application where you know the numbers are prime you
# will remove this function (and the call). If you need to
# test for primality, look for a more efficient algorithm, see
# for example Joseph F's answer on this page.
i = 2
while i*i <= possible:
if (possible % i) == 0:
return True
i = i + 1
return False
def primRoots(theNum):
if isNotPrime(theNum):
raise ValueError("Sorry, the number must be prime.")
o = 1
roots = []
r = 2
while r < theNum:
k = pow(r, o, theNum)
while (k > 1):
o = o + 1
k = (k * r) % theNum
if o == (theNum - 1):
roots.append(r)
o = 1
r = r + 1
return roots
print(primRoots(int(sys.argv[1])))
You can greatly improve your isNotPrime function by using a more efficient algorithm. You could double the speed by doing a special test for even numbers and then only testing odd numbers up to the square root, but this is still very inefficient compared to an algorithm such as the Miller Rabin test. This version in the Rosetta Code site will always give the correct answer for any number with fewer than 25 digits or so. For large primes, this will run in a tiny fraction of the time it takes to use trial division.
Also, you should avoid using the floating point exponentiation operator ** when you are dealing with integers as in this case (even though the Rosetta code that I just linked to does the same thing!). Things might work fine in a particular case, but it can be a subtle source of error when Python has to convert from floating point to integers, or when an integer is too large to represent exactly in floating point. There are efficient integer square root algorithms that you can use instead. Here's a simple one:
def int_sqrt(n):
if n == 0:
return 0
x = n
y = (x + n//x)//2
while (y<x):
x=y
y = (x + n//x)//2
return x
Those codes are all in-efficient, in many ways, first of all you do not need to iterate for all co-prime reminders of n, you need to check only for powers that are dividers of Euler's function from n. In the case n is prime Euler's function is n-1. If n i prime, you need to factorize n-1 and make check with only those dividers, not all. There is a simple mathematics behind this.
Second. You need better function for powering a number imagine the power is too big, I think in python you have the function pow(g, powers, modulo) which at each steps makes division and getting the remainder only ( _ % modulo ).
If you are going to implement the Diffie-Hellman algorithm it is better to use safe primes. They are such primes that p is a prime and 2p+1 is also prime, so that 2p+1 is called safe prime. If you get n = 2*p+1, then the dividers for that n-1 (n is prime, Euler's function from n is n-1) are 1, 2, p and 2p, you need to check only if the number g at power 2 and g at power p if one of them gives 1, then that g is not primitive root, and you can throw that g away and select another g, the next one g+1, If g^2 and g^p are non equal to 1 by modulo n, then that g is a primitive root, that check guarantees, that all powers except 2p would give numbers different from 1 by modulo n.
The example code uses Sophie Germain prime p and the corresponding safe prime 2p+1, and calculates primitive roots of that safe prime 2p+1.
You can easily re-work the code for any prime number or any other number, by adding a function to calculate Euler's function and to find all divisors of that value. But this is only a demo not a complete code. And there might be better ways.
class SGPrime :
'''
This object expects a Sophie Germain prime p, it does not check that it accept that as input.
Euler function from any prime is n-1, and the order (see method get_order) of any co-prime
remainder of n could be only a divider of Euler function value.
'''
def __init__(self, pSophieGermain ):
self.n = 2*pSophieGermain+1
#TODO! check if pSophieGermain is prime
#TODO! check if n is also prime.
#They both have to be primes, elsewhere the code does not work!
# Euler's function is n-1, #TODO for any n, calculate Euler's function from n
self.elrfunc = self.n-1
# All divisors of Euler's function value, #TODO for any n, get all divisors of the Euler's function value.
self.elrfunc_divisors = [1, 2, pSophieGermain, self.elrfunc]
def get_order(self, r):
'''
Calculate the order of a number, the minimal power at which r would be congruent with 1 by modulo p.
'''
r = r % self.n
for d in self.elrfunc_divisors:
if ( pow( r, d, self.n) == 1 ):
return d
return 0 # no such order, not possible if n is prime, - see small Fermat's theorem
def is_primitive_root(self, r):
'''
Check if r is a primitive root by modulo p. Such always exists if p is prime.
'''
return ( self.get_order(r) == self.elrfunc )
def find_all_primitive_roots(self, max_num_of_roots = None):
'''
Find all primitive roots, only for demo if n is large the list is large for DH or any other such algorithm
better to stop at first primitive roots.
'''
primitive_roots = []
for g in range(1, self.n):
if ( self.is_primitive_root(g) ):
primitive_roots.append(g)
if (( max_num_of_roots != None ) and (len(primitive_roots) >= max_num_of_roots)):
break
return primitive_roots
#demo, Sophie Germain's prime
p = 20963
sggen = SGPrime(p)
print (f"Safe prime : {sggen.n}, and primitive roots of {sggen.n} are : " )
print(sggen.find_all_primitive_roots())
Regards

Factoring a number into roughly equal factors

I would like to decompose a number into a tuple of numbers as close to each other in size as possible, whose product is the initial number. The inputs are the number n we want to factor and the number m of factors desired.
For the two factor situation (m==2), it is enough to look for the largest factor less than a square root, so I can do something like this
def get_factors(n):
i = int(n**0.5 + 0.5)
while n % i != 0:
i -= 1
return i, n/i
So calling this with 120 will result in 10,12.
I realize there is some ambiguity as to what it means for the numbers to be "close to each other in size". I don't mind if this is interpretted as minimizing Σ(x_i - x_avg) or Σ(x_i - x_avg)^2 or something else generally along those lines.
For the m==3 case, I would expect that 336 to produce 6,7,8 and 729 to produce 9,9,9.
Ideally, I would like a solution for general m, but if someone has an idea even for m==3 it would be much appreciated. I welcome general heuristics too.
EDIT: I would prefer to minimize the sum of the factors. Still interested in the above, but if someone has an idea for a way of also figuring out the optimal m value such that the sum of factors is minimal, it'd be great!
To answer your second question (which m minimizes the sum of factors), it will always be optimal to split number into its prime factors. Indeed, for any positive composite number except 4 sum of its prime factors is less that the number itself, so any split that has composite numbers can be improved by splitting that composite numbers into its prime factors.
To answer your first question, greedy approaches suggested by others will not work, as I pointed out in the comments 4104 breaks them, greedy will immediately extract 8 as the first factor, and then will be forced to split the remaining number into [3, 9, 19], failing to find a better solution [6, 6, 6, 19]. However, a simple DP can find the best solution. The state of the DP is the number we are trying to factor, and how many factors do we want to get, the value of the DP is the best sum possible. Something along the lines of the code below. It can be optimized by doing factorization smarter.
n = int(raw_input())
left = int(raw_input())
memo = {}
def dp(n, left): # returns tuple (cost, [factors])
if (n, left) in memo: return memo[(n, left)]
if left == 1:
return (n, [n])
i = 2
best = n
bestTuple = [n]
while i * i <= n:
if n % i == 0:
rem = dp(n / i, left - 1)
if rem[0] + i < best:
best = rem[0] + i
bestTuple = [i] + rem[1]
i += 1
memo[(n, left)] = (best, bestTuple)
return memo[(n, left)]
print dp(n, left)[1]
For example
[In] 4104
[In] 4
[Out] [6, 6, 6, 19]
You can start with the same principle: look for numbers under or equal to the mth root that are factors. Then you can recurse to find the remaining factors.
def get_factors(n, m):
factors = []
factor = int(n**(1.0/m) + .1) # fudged to deal with precision problem with float roots
while n % factor != 0:
factor = factor - 1
factors.append(factor)
if m > 1:
factors = factors + get_factors(n / factor, m - 1)
return factors
print get_factors(729, 3)
How about this, for m=3 and some n:
Get the largest factor of n smaller than the cube root of n, call it f1
Divide n by f1, call it g
Find the "roughly equal factors" of g as in the m=2 example.
For 336, the largest factor smaller than the cube root of 336 is 6 (I think). Dividing 336 by 6 gives 56 (another factor, go figure!) Performing the same math for 56 and looking for two factors, we get 7 and 8.
Note that doesn't work for any number with fewer than 3 factors. This method can be expanded for m > 3, maybe.
If this is right, and I'm not too crazy, the solution would be a recursive function:
factors=[]
n=336
m=3
def getFactors(howMany, value):
if howMany < 2:
return value
root=getRoot(howMany, value) # get the root of value, eg square root, cube, etc.
factor=getLargestFactor(value, root) # get the largest factor of value smaller than root
otherFactors=getFactors(howMany-1, value / factor)
otherFactors.insert(factor)
return otherFactors
print getFactors(n, m)
I'm too lazy to code the rest, but that should do it.
m=5 n=4 then m^(1/n)
you get:
Answer=1.495
then
1.495*1.495*1.495*1.495 = 5
in C#
double Result = Math.Pow(m,1/(double)n);

Efficient calculation of Fibonacci series

I'm working on a Project Euler problem: the one about the sum of the even Fibonacci numbers.
My code:
def Fibonacci(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return Fibonacci(n-1) + Fibonacci(n-2)
list1 = [x for x in range(39)]
list2 = [i for i in list1 if Fibonacci(i) % 2 == 0]
The problem's solution can be easily found by printing sum(list2). However, it is taking a lot of time to come up with the list2 I'm guessing. Is there any way to make this faster? Or is it okay even this way...
(the problem: By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.)
Yes. The primitive recursive solution takes a lot of time. The reason for this is that for each number calculated, it needs to calculate all the previous numbers more than once. Take a look at the following image.
It represents calculating Fibonacci(5) with your function. As you can see, it computes the value of Fibonacci(2) three times, and the value of Fibonacci(1) five times. That just gets worse and worse the higher the number you want to compute.
What makes it even worse is that with each fibonacci number you calculate in your list, you don't use the previous numbers you have knowledge of to speed up the computation – you compute each number "from scratch."
There are a few options to make this faster:
1. Create a list "from the bottom up"
The easiest way is to just create a list of fibonacci numbers up to the number you want. If you do that, you build "from the bottom up" or so to speak, and you can reuse previous numbers to create the next one. If you have a list of the fibonacci numbers [0, 1, 1, 2, 3], you can use the last two numbers in that list to create the next number.
This approach would look something like this:
>>> def fib_to(n):
... fibs = [0, 1]
... for i in range(2, n+1):
... fibs.append(fibs[-1] + fibs[-2])
... return fibs
...
Then you can get the first 20 fibonacci numbers by doing
>>> fib_to(20)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]
Or you can get the 17th fibonacci number from a list of the first 40 by doing
>>> fib_to(40)[17]
1597
2. Memoization (relatively advanced technique)
Another alternative to make it faster exists, but it is a little more complicated as well. Since your problem is that you re-compute values you have already computed, you can instead choose to save the values you have already computed in a dict, and try to get them from that before you recompute them. This is called memoization. It may look something like this:
>>> def fib(n, computed = {0: 0, 1: 1}):
... if n not in computed:
... computed[n] = fib(n-1, computed) + fib(n-2, computed)
... return computed[n]
This allows you to compute big fibonacci numbers in a breeze:
>>> fib(400)
176023680645013966468226945392411250770384383304492191886725992896575345044216019675
This is in fact such a common technique that Python 3 includes a decorator to do this for you. I present to you, automatic memoization!
import functools
#functools.lru_cache(None)
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
This does pretty much the same thing as the previous function, but with all the computed stuff handled by the lru_cache decorator.
3. Just count up (a naïve iterative solution)
A third method, as suggested by Mitch, is to just count up without saving the intermediary values in a list. You could imagine doing
>>> def fib(n):
... a, b = 0, 1
... for _ in range(n):
... a, b = b, a+b
... return a
I don't recommend these last two methods if your goal is to create a list of fibonacci numbers. fib_to(100) is going to be a lot faster than [fib(n) for n in range(101)] because with the latter, you still get the problem of computing each number in the list from scratch.
This is a very fast algorithm and it can find n-th Fibonacci number much faster than simple iterative approach presented in other answers, it is quite advanced though:
def fib(n):
v1, v2, v3 = 1, 1, 0 # initialise a matrix [[1,1],[1,0]]
for rec in bin(n)[3:]: # perform fast exponentiation of the matrix (quickly raise it to the nth power)
calc = v2*v2
v1, v2, v3 = v1*v1+calc, (v1+v3)*v2, calc+v3*v3
if rec=='1': v1, v2, v3 = v1+v2, v1, v2
return v2
You can read some more about involved math here.
Python doesn't optimize tail recursion, thus most solutions presented here will fail with Error: maximum recursion depth exceeded in comparison if n is too big (and by big, I mean 1000).
The recursion limit can be increased, but it will make Python crash on stack overflow in the operating system.
Note the difference in performance between fib_memo / fib_local and fib_lru / fib_local_exc: LRU cache is a lot slower and didn't even complete, because it produces a runtime error already for n = ~500:
import functools
from time import clock
#import sys
#sys.setrecursionlimit()
#functools.lru_cache(None)
def fib_lru(n):
if n < 2:
return n
return fib_lru(n-1) + fib_lru(n-2)
def fib_memo(n, computed = {0: 0, 1: 1}):
if n not in computed:
computed[n] = fib_memo(n-1, computed) + fib_memo(n-2, computed)
return computed[n]
def fib_local(n):
computed = {0: 0, 1: 1}
def fib_inner(n):
if n not in computed:
computed[n] = fib_inner(n-1) + fib_inner(n-2)
return computed[n]
return fib_inner(n)
def fib_local_exc(n):
computed = {0: 0, 1: 1}
def fib_inner_x(n):
try:
computed[n]
except KeyError:
computed[n] = fib_inner_x(n-1) + fib_inner_x(n-2)
return computed[n]
return fib_inner_x(n)
def fib_iter(n):
a, b = 0, 1
for i in range(n):
a, b = b, a + b
return a
def benchmark(n, *args):
print("-" * 80)
for func in args:
print(func.__name__)
start = clock()
try:
ret = func(n)
#print("Result:", ret)
except RuntimeError as e:
print("Error:", e)
print("Time:", "{:.8f}".format(clock() - start))
print()
benchmark(500, fib_iter, fib_memo, fib_local, fib_local_exc, fib_lru)
Results:
fib_iter
Time: 0.00008168
fib_memo
Time: 0.00048622
fib_local
Time: 0.00044645
fib_local_exc
Time: 0.00146036
fib_lru
Error: maximum recursion depth exceeded in comparison
Time: 0.00112552
The iterative solution is by far the fastest and does not corrupt the stack even for n=100k (0.162 seconds). It does not return the intermediate Fibonacci numbers indeed.
If you want to compute the nth even Fibonacci number, you could adapt the iterative approach like this:
def fib_even_iter(n):
a, b = 0, 1
c = 1
while c < n:
a, b = b, a + b
if a % 2 == 0:
c += 1
return a
Or if you are interested in every even number on the way, use a generator:
def fib_even_gen(n):
a, b = 0, 1
c = 1
yield a
while c < n:
a, b = b, a + b
if a % 2 == 0:
yield a
c += 1
return a
for i, f in enumerate(fib_even_gen(100), 1):
print("{:3d}. {:d}".format(i, f))
Result:
1. 0
2. 2
3. 8
4. 34
5. 144
6. 610
7. 2584
8. 10946
9. 46368
10. 196418
11. 832040
12. 3524578
13. 14930352
14. 63245986
15. 267914296
16. 1134903170
17. 4807526976
18. 20365011074
19. 86267571272
20. 365435296162
21. 1548008755920
22. 6557470319842
23. 27777890035288
24. 117669030460994
25. 498454011879264
26. 2111485077978050
27. 8944394323791464
28. 37889062373143906
29. 160500643816367088
30. 679891637638612258
31. 2880067194370816120
32. 12200160415121876738
33. 51680708854858323072
34. 218922995834555169026
35. 927372692193078999176
36. 3928413764606871165730
37. 16641027750620563662096
38. 70492524767089125814114
39. 298611126818977066918552
40. 1264937032042997393488322
41. 5358359254990966640871840
42. 22698374052006863956975682
43. 96151855463018422468774568
44. 407305795904080553832073954
45. 1725375039079340637797070384
46. 7308805952221443105020355490
47. 30960598847965113057878492344
48. 131151201344081895336534324866
49. 555565404224292694404015791808
50. 2353412818241252672952597492098
51. 9969216677189303386214405760200
52. 42230279526998466217810220532898
53. 178890334785183168257455287891792
54. 757791618667731139247631372100066
55. 3210056809456107725247980776292056
56. 13598018856492162040239554477268290
57. 57602132235424755886206198685365216
58. 244006547798191185585064349218729154
59. 1033628323428189498226463595560281832
60. 4378519841510949178490918731459856482
61. 18547707689471986212190138521399707760
62. 78569350599398894027251472817058687522
63. 332825110087067562321196029789634457848
64. 1409869790947669143312035591975596518914
65. 5972304273877744135569338397692020533504
66. 25299086886458645685589389182743678652930
67. 107168651819712326877926895128666735145224
68. 453973694165307953197296969697410619233826
69. 1923063428480944139667114773918309212080528
70. 8146227408089084511865756065370647467555938
71. 34507973060837282187130139035400899082304280
72. 146178119651438213260386312206974243796773058
73. 619220451666590135228675387863297874269396512
74. 2623059926317798754175087863660165740874359106
75. 11111460156937785151929026842503960837766832936
76. 47068900554068939361891195233676009091941690850
77. 199387062373213542599493807777207997205533596336
78. 844617150046923109759866426342507997914076076194
79. 3577855662560905981638959513147239988861837901112
80. 15156039800290547036315704478931467953361427680642
81. 64202014863723094126901777428873111802307548623680
82. 271964099255182923543922814194423915162591622175362
83. 1152058411884454788302593034206568772452674037325128
84. 4880197746793002076754294951020699004973287771475874
85. 20672849399056463095319772838289364792345825123228624
86. 87571595343018854458033386304178158174356588264390370
87. 370959230771131880927453318055001997489772178180790104
88. 1571408518427546378167846658524186148133445300987550786
89. 6656593304481317393598839952151746590023553382130993248
90. 28197781736352815952563206467131172508227658829511523778
91. 119447720249892581203851665820676436622934188700177088360
92. 505988662735923140767969869749836918999964413630219877218
93. 2143402371193585144275731144820024112622791843221056597232
94. 9079598147510263717870894449029933369491131786514446266146
95. 38461794961234640015759308940939757590587318989278841661816
96. 162926777992448823780908130212788963731840407743629812913410
97. 690168906931029935139391829792095612517948949963798093315456
98. 2923602405716568564338475449381171413803636207598822186175234
99. 12384578529797304192493293627316781267732493780359086838016392
100. 52461916524905785334311649958648296484733611329035169538240802
Time: 0.00698620
That's the first 100 even Fibonacci numbers in ~7ms and includes the overhead of printing to terminal (easy to underestimate on Windows).
Based on the fact that fib(n) = fib(n-1)+fib(n-2), the straightforward solution is
def fib(n):
if (n <=1):
return(1)
else:
return(fib(n-1)+fib(n-2))
however, the problem here is that some values are calculated multiple times, and therefore it is very inefficient. The reason can be seen in this sketch:
Essentially, each recursive call to fib function has to compute all the previous fibonacci numbers for its own use. So, the most computed value will be fib(1) since it has to appear in all the leaf nodes of the tree shown by answer of #kqr. The complexity of this algorithm is the number of nodes of the tree, which is $O(2^n)$.
Now a better way is to keep track of two numbers, the current value and the previous value, so each call does not have to compute all the previous values. This is the second algorithm in the sketch, and can be implemented as follows
def fib(n):
if (n==0):
return(0,1)
elif (n==1):
return(1,1)
else:
a,b = fib(n-1)
return(b,a+b)
The complexity of this algorithm is linear $O(n)$, and some examples will be
>>> fib(1)
(1, 1)
>>> fib(2)
(1, 2)
>>> fib(4)
(3, 5)
>>> fib(6)
(8, 13)
I based this on an article on Fibonacci numbers on Wikipedia. The idea is to avoid looping and recursion and simply calculate the value as needed.
Not being a math wiz, selected one of the formulas and rendered it to code and tweaked it until the values came out right.
import cmath
def getFib(n):
#Given which fibonacci number we want, calculate its value
lsa = (1 / cmath.sqrt(5)) * pow(((1 + cmath.sqrt(5)) / 2), n)
rsa = (1 / cmath.sqrt(5)) * pow(((1 - cmath.sqrt(5)) / 2), n)
fib = lsa-rsa
#coerce to real so we can round the complex result
fn = round(fib.real)
return fn
#Demo using the function
s = ''
for m in range(0,30):
s = s + '(' + str(m) + ')' + str(getFib(m)) + ' '
print(s)
An O(1) solution
It turns out that there is a nice recursive formula for the sum of even Fibonacci numbers. The nth term in the sequence of sums of even Fibonacci numbers is S_{n} = 4*S_{n-1} + S_{n-2} + 2 Proof is left to the reader, but involves proving 1) even Fibo numbers are every third one, 2) proof of the formula above with induction using the definition of Fibo numbers. Using the logic from here, we can derive a closed-form formula for this with a little effort:
S_{n} = -1/2 + (1/4 + 3*sqrt(5)/20)*(2+sqrt(5))**n + (1/4 - 3*sqrt(5)/20)*(2-sqrt(5))**n
Despite the sqrt, this is integral for integral n, so this can be conveniently computed using the handy functions from my previous answer, or using a package such as sympy to handle the roots exactly.
import sympy as sp
one = sp.sympify(1) #to force casting to sympy types
k1 = -one/2
k2 = one/4 + 3*sp.sqrt(5)/20
k3 = one/4 - 3*sp.sqrt(5)/20
r1 = one
r2 = 2 + sp.sqrt(5)
r3 = 2 - sp.sqrt(5)
def even_sum_fibo(n):
#get the nth number in the sequence of even sums of Fibonacci numbers. If you want the sum of Fibos up to some number m, use n = m/3 (integer division)
return sp.simplify(k1*r1**n + k2*r2**n + k3*r3**n)
Here's a simple one without recursion and O(n)
def fibonacci(n):
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
return a
Spoiler alert: don't read this if you're doing Project Euler Question 2 until you've had a crack at it yourself.
Closed-form series-summation-based approaches aside, this seems more efficient than most/all of what I've seen posted, as it only needs one rather cheap loop iteration per even Fibonacci number, so only 12 iterations to get to 4,000,000.
def sumOfEvenFibonacciNumbersUpTo(inclusiveLimit):
even = 0
next = 1
sum = 0
while even<=inclusiveLimit:
sum += even
even += next<<1
next = (even<<1)-next
return sum
import time
def calculate_fibonacci_1(n):
if n == 0:
return 0
if n == 1:
return 1
return calculate_fibonacci_1(n - 1) + calculate_fibonacci_1(n - 2)
def calculate_fibonacci_2(n):
fib = [0] * n
fib[0] = 1
fib[1] = 1
for i in range(2, n):
fib[i] = fib[i - 1] + fib[i - 2]
return fib[n-1]
def calculate_fibonacci_3(n):
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
return a
def calculate_fibonacci_4(n):
v1, v2, v3 = 1, 1, 0
for rec in bin(n)[3:]:
calc = v2*v2
v1, v2, v3 = v1*v1+calc, (v1+v3)*v2, calc+v3*v3
if rec == '1':
v1, v2, v3 = v1+v2, v1, v2
return v2
def calculate_fibonacci_5(n):
if n == 0:
return (0, 1)
else:
a, b = calculate_fibonacci_5(n // 2)
c = a * (b * 2 - a)
d = a * a + b * b
if n % 2 == 0:
return (c, d)
else:
return (d, c + d)
n = 30
start = time.time()
calculate_fibonacci_1(n)
end = time.time()
print(end - start)
start = time.time()
calculate_fibonacci_2(n)
end = time.time()
print(end - start)
start = time.time()
calculate_fibonacci_3(n)
end = time.time()
print(end - start)
start = time.time()
calculate_fibonacci_4(n)
end = time.time()
print(end - start)
start = time.time()
calculate_fibonacci_5(n)
end = time.time()
print(end - start)
for n=30:
0.264876127243
6.19888305664e-06
8.10623168945e-06
7.15255737305e-06
4.05311584473e-06
for n=300:
>10s
3.19480895996e-05
1.78813934326e-05
7.15255737305e-06
6.19888305664e-06
for n=3000:
>10s
0.000766038894653
0.000277996063232
1.78813934326e-05
1.28746032715e-05
for n=30000:
>10s
0.0550990104675
0.0153529644012
0.000290870666504
0.000216007232666
for n=300000:
>10s
3.35211610794
0.979753017426
0.012097120285
0.00845909118652
for n=3000000:
>10s
>10s
>10s
0.466345071793
0.355515003204
for n=30000000:
>100s
>100s
>100s
16.4943139553
12.6505448818
disclaimer: codes of functions no. 4 and 5 were not written by me
kqr's solution nr 2 is my definite favourite.
However in this specific case we are loosing all our calculations between consequent calls within the list comprehension:
list2 = [i for i in list1 if fib(i) % 2 == 0]
, so I decided to go one step further and memoize it between loop steps as follows:
def cache_fib(ff):
comp = {0: 0, 1: 1}
def fib_cached(n, computed=comp):
return ff(n, computed)
return fib_cached
#cache_fib
def fib(n, computed={0: 0, 1: 1}):
if n not in computed:
computed[n] = fib(n - 1, computed) + fib(n - 2, computed)
return computed[n]
Solution in R, benchmark calculates 1 to 1000th Fibonacci number series in 1.9 seconds. Would be much faster in C++ or Fortran, in fact, since writing the initial post, I wrote an equivalent function in C++ which completed in an impressive 0.0033 seconds, even python completed in 0.3 seconds.
#Calculate Fibonnaci Sequence
fib <- function(n){
if(n <= 2)
return(as.integer(as.logical(n)))
k = as.integer(n/2)
a = fib(k + 1)
b = fib(k)
if(n %% 2 == 1)
return(a*a + b*b)
return(b*(2*a - b))
}
#Function to do every fibonacci number up to nmax
doFib <- function(nmax = 25,doPrint=FALSE){
res = sapply(0:abs(nmax),fib)
if(doPrint)
print(paste(res,collapse=","))
return(res)
}
#Benchmark
system.time(doFib(1000))
#user system elapsed
# 1.874 0.007 1.892
There is an O(1) solution: https://en.wikipedia.org/wiki/Fibonacci_number#Computation_by_rounding
import math
PHI = (1 + math.sqrt(5)) / 2
SQRT5 = math.sqrt(5)
def fast_fib(n):
if n < 0:
raise ValueError('Fibs for negative values are not defined.')
return round(math.pow(PHI, n) / SQRT5)
I realize this question was asked 8 years ago and it's been thoroughly answered… sorry to bounce it back up to the top. But there is always more to be said. I came across this in a search to improve my own algorithm, which I'd like to share.
I'd like to offer my own take since I see this wasn't really brought up. I think my algorithm is unique amongst the contributors thus far. I make use of well known Fibonacci number equations (wikipedia) in order to scale down the index. One or two others briefly cover a basic version, but I take it a step further.
This is a recursive algorithm, but I'm able to calculate Fib(2 million) in 0.15 seconds, Fib(10 million) in under 2 seconds, and Fib(100 million) in 75 seconds. All without error. I will say this, it isn't the fastest for calculating a whole list of consecutive Fibonacci numbers; this is best for picking out individuals that are very large.
Most algorithms mentioned so far - no matter how fast they may be - struggle to get above Fib(100) without recursion depth issues. A couple of contributors have eluded to parts of my algorithm, though they have some disadvantages that mine doesn't. Not saying mines the best or anything, but I think it's quite fast and can calculate really large fibs. I think it's worth adding to the discussion.
Best of all, I don't make any use of memory. No lists, dictionaries or arrays of any kind. No caches or memoization. Not even a single persistent saved constant. No special packages imported. Just basic, plain, python with basic integer types. Ive also extended the function to compute negative fibs with negligible impact to run time.
I should warn though… I'm a mathematician, not a programmer. I have no doubts this can be improved further. And I have no idea what the Big O is.
def fib(n):
if n<0: return int(pow(-1, (n&1)+1))*fib(-n)
if n == 0: return 0
if n==1 or n==2: return 1
if n==3: return 2
# n is multiple of 3
if n%3 == 0:
third = n//3
fibthird = fib(third)
return 5*pow(fibthird,3) + 3*pow(-1, third)*fibthird
# even n
if n&1==0:
return pow(fib((n>>1) + 1),2) - pow(fib((n>>1) - 1), 2)
# for odd n
return ( pow(fib((n>>1)+1),2) + pow(fib(n>>1),2) )
Run the code, tell me what you think. I'd love to hear from the community. I'm impressed by it, personally, and have been running it for a while. Can't find a way in my limited (programming) knowledge to improve it though. Trying to add lists, memoization, caches, etc., either fails to improve anything, or makes runtime worse. In the rare instance I find something that improves runtime, the benefits to runtime are negligible and the costs to memory are significant, and I don't think it's a fair trade.
Prime testing
For added fun, I include a basic probabilistic is_prime test below that relates to Fibonacci numbers:
def is_prime_fib(n):
# Fibonacci Probabilistic is_prime test. Compositeness deterministic.
if n==1: return False
if n==5: return True
if n%5 in [1,4] and fib(n-1) % n == 0: return True
if n%5 in [2,3] and fib(n+1) % n == 0: return True
return False
I include this just for fun even though its off topic. Its a well-known primality test using fibonacci numbers, but unfortunately it goes unused precisely because most fibonacci calculating algorithms are slow, cause recursion error, or otherwise produce inaccuracies, thus making the test unreliable and we naturally resort to other algorithms. I think the game can be changed a bit though.
On its own, the Fibonacci primality test is probabilistic. The n=1 and n=5 cases are oddities that fail to produce correct results, but they are too obvious to worry about. Aside from that, a False is deterministic in compositeness, a True is probabilistic in primeness. A composite that passes as true by this test is a Fibonacci Pseudoprime. In conjunction with other probabilistic tests, we can achieve emergent determinism.
Any problems like this will take a long time to run if there are a lot of levels of recursion. The recursive definition is good for coding the problem in a way that can be easily understood, but if you need it to run faster an iterative solution such as the answer in this thread will be much quicker.
Recursively calculating Fibonacci will be most inefficient than doing iteratively. My recommendation is:
Take the time to create a Fibonacci class as an iterator, and do the calculations independently for each element in the index, maybe with some #memoize decorator (and also here) to cache all previous calculations.
Hope this helps!
One fast way is to calculate the fib(n/2) number recursively:
fibs = {0: 0, 1: 1}
def fib(n):
if n in fibs: return fibs[n]
if n % 2 == 0:
fibs[n] = ((2 * fib((n / 2) - 1)) + fib(n / 2)) * fib(n / 2)
return fibs[n]
else:
fibs[n] = (fib((n - 1) / 2) ** 2) + (fib((n+1) / 2) ** 2)
return fibs[n]
from time import time
s=time()
print fib(1000000)
print time()-s
Haskell 1 liner :-
fibs = 0 : (f 1 1) where f a b = a : f b (a+b)
This code is extremely efficient and calculates Fibonacci numbers up to (10^1000) in less than a second !
This code will also be useful for this problem in Project Euler.
To find the sum of the first n even-valued fibonacci numbers directly, put 3n + 2 in your favourite method to efficiently compute a single fibonacci number, decrement by one and divide by two (fib((3*n+2) - 1)/2)). How did math dummies survive before OEIS?
This is some improved version of Fibonacci where we compute Fibonacci of number only once:
dicFib = { 0:0 ,1 :1 }
iterations = 0
def fibonacci(a):
if (a in dicFib):
return dicFib[a]
else :
global iterations
fib = fibonacci(a-2)+fibonacci(a-1)
dicFib[a] = fib
iterations += 1
return fib
print ("Fibonacci of 10 is:" , fibonacci(10))
print ("Fibonacci of all numbers:" ,dicFib)
print ("iterations:" ,iterations)
# ('Fibonacci of 10 is:', 55)
# ('Fibonacci of all numbers:', {0: 0, 1: 1, 2: 1, 3: 2, 4: 3, 5: 5, 6: 8, 7: 13, 8: 21, 9: 34, 10: 55})
# ('iterations:', 9)
Here we are storing Fibonacci of each number in dictionary. So you can see it calculates only once for each iteration and for Fibonacci(10) it is only 9 times.
O(1) SOLUTION
The formula is also called Binet's Formula (read more)
Basically, we can write it in python like this:
def fib(n):
a = ((1 + (5 ** 0.5)) / 2)**int(n)
b = ((1 - (5 ** 0.5)) / 2)**int(n)
return round((a - b) / (5 ** 0.5))
However, Because of the relatively low value of b, we can ignore it and the function can be as simple as
def fib(n):
return round((((1+(5**0.5))/2)**int(n))/(5**0.5))
You can use the equation with square roots to compute this if you don't use floating point arithmetic, but keep track of the coefficients some other way as you go. This gives an O(log n) arithmetic operation (as opposed to O(n log n) operations for memoization) algorithm.
def rootiply(a1,b1,a2,b2,c):
''' multipy a1+b1*sqrt(c) and a2+b2*sqrt(c)... return a,b'''
return a1*a2 + b1*b2*c, a1*b2 + a2*b1
def rootipower(a,b,c,n):
''' raise a + b * sqrt(c) to the nth power... returns the new a,b and c of the result in the same format'''
ar,br = 1,0
while n != 0:
if n%2:
ar,br = rootiply(ar,br,a,b,c)
a,b = rootiply(a,b,a,b,c)
n /= 2
return ar,br
def fib(k):
''' the kth fibonacci number'''
a1,b1 = rootipower(1,1,5,k)
a2,b2 = rootipower(1,-1,5,k)
a = a1-a2
b = b1-b2
a,b = rootiply(0,1,a,b,5)
# b should be 0!
assert b == 0
return a/2**k/5
if __name__ == "__main__":
assert rootipower(1,2,3,3) == (37,30) # 1+2sqrt(3) **3 => 13 + 4sqrt(3) => 39 + 30sqrt(3)
assert fib(10)==55
Just another one fast solution:
def fibonnaci(n):
a = []
while n != 1:
a.append(n&1)
n >>= 1
f1 = 1
f2 = 1
while a:
t = f1 * (f2 * 2 - f1)
f2 = f2 * f2 + f1 * f1
if a.pop() is 1:
f1 = f2
f2 += t
else:
f1 = t
return f1
I had done a little research and found out about a formula called Binet's formula.
This formula can calculate the nth number of the fibonacci sequence easily in O(1) time.
Here is my Java code translated to Python:
def fibonacci(n):
five_sqrt = 5 ** 0.5
return int(round((((1 + five_sqrt)/2) ** n)/five_sqrt))
for i in range(1, 21):
print(fibonacci(i))
Output:
1,
1,
2,
3,
5,
8,
13,
21,
34,
55,
89,
144,
233,
377,
610,
987,
1597,
2584,
4181,
6765
I know this is an old question but I figured I would give it a go anyways.
First, some basics. Every third Fibonacci number is even. Since F(1)+F(2)=F(3), F(4)+F(5)=F(6), etc, all the even Fibonacci numbers make up half the total sum of all Fibonacci numbers up to F(3X). We already have an easy way to find the sum of all Fibonacci numbers up to F(X). The answer is F(X+2)-1. All we have to do is divide that term by two and we have our answer.
Now a little sidetracking to how we solve Fibonacci in O(log2(X)) time. Phi is a very special number. Phi=(sqrt(5)+1)/2. Phi^2=1+Phi. In fact, Phi^X=F(X-1)+F(X)Phi. Bringing back highschool algebra, we know Phi^2X=(Phi^X)^2 = (F(X-1)+F(X)Phi)^2 = F(X-1)^2+2F(X-1)F(X)Phi+(F(X)^2)(Phi^2). We know Phi^2, so substitute and distribute. F(2X-1)+F(2X)Phi=Phi^2X=F(X-1)^2+F(X)^2+Phi(2F(X-1)F(X)+F(X)^2). Since Fibonacci numbers are integers that don't contain Phi, we now know that F(2X-1)=F(X-1)^2+F(X)^2. With the additional fact that F(2X+1)=F(X)+F(X+1), we can find F(2X)=F(X+1)^2-F(X-1)^2. Now lets code!
import math
def fibonacci(x):
a=1 #start at F(-1)
b=0 #start at F(0)
c=1 #start at F(1)
bits=int((math.log2(x)+1)//1) #number of bits in x
for i in range(bits,-1,-1):
#Times 2
d=b*b+a*a
e=c*c-a*a
f=d+e
a=d
b=e
c=f
bit=(x//(2**i))%2
#Plus 1
if bit==1:
a=b
b=c
c=a+b
return b
def fibsum(x):
y=x-(x%3)
return (fibonacci(y+2)-1)//2
print(fibsum(600))
Since Python 3.9, you can use the cache decorator. From the docs:
Returns the same as lru_cache(maxsize=None), creating a thin wrapper around a dictionary lookup for the function arguments. Because it never needs to evict old values, this is smaller and faster than lru_cache() with a size limit.
from functools import cache
#cache
def fibonacci(n):
if (n==2) or (n==1):
return 1
else:
return fibonacci(n-1) + fibonacci(n-2)
Although a late answer but it might be helpful
fib_dict = {}
def fib(n):
try:
return fib_dict[n]
except:
if n<=1:
fib_dict[n] = n
return n
else:
fib_dict[n] = fib(n-1) + fib (n-2)
return fib(n-1) + fib (n-2)
print fib(100)
This is much faster than the traditional way
Given the starting number and the maximum number; I think the following solution for fibonacci would be interesting. The good thing is that it doesn't include recursion - thus reducing memory burden.
# starting number is a
# largest number in the fibonacci sequence is b
def fibonacci(a,b):
fib_series = [a, a]
while sum(fib_series[-2:]) <=b:
next_fib = sum(fib_series[-2:])
fib_series.append(next_fib)
return fib_series
print('the fibonacci series for the range %s is %s'
%([3, 27], fibonacci(3, 27)))
the fibonacci series for the range [1, 12] is [3, 3, 6, 9, 15, 24]
Here is an Optimized Solution with the Dictionary
def Fibonacci(n):
if n<2 : return n
elif not n in fib_dict :
fib_dict[n]= Fibonacci(n-1) + Fibonacci(n-2)
return fib_dict[n]
#dictionary which store Fibonacci values with the Key
fib_dict = {}
print(Fibonacci(440))
This is much faster than everything above
from sympy import fibonacci
%timeit fibonacci(10000)
262 ns ± 10.8 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Here are some more formulas, from OEIS:
F(n) = ((1+sqrt(5))^n - (1-sqrt(5))^n)/(2^n*sqrt(5))
Alternatively, F(n) = ((1/2+sqrt(5)/2)^n - (1/2-sqrt(5)/2)^n)/sqrt(5)
F(n) = round(phi^n/sqrt(5)); where phi is (1 + sqrt(5)) / 2
F(n+1) = Sum_{j=0..floor(n/2)} binomial(n-j, j)
Some of these formulas have implementations in the other comments above.

Categories

Resources