Create faster Fibonacci function for n > 100 in MATLAB / octave - matlab

I have a function that tells me the nth number in a Fibonacci sequence. The problem is it becomes very slow when trying to find larger numbers in the Fibonacci sequence does anyone know how I can fix this?
function f = rtfib(n)
if (n==1)
f= 1;
elseif (n == 2)
f = 2;
else
f =rtfib(n-1) + rtfib(n-2);
end
The Results,
tic; rtfib(20), toc
ans = 10946
Elapsed time is 0.134947 seconds.
tic; rtfib(30), toc
ans = 1346269
Elapsed time is 16.6724 seconds.
I can't even get a value after 5 mins doing rtfib(100)
PS: I'm using octave 3.8.1

If time is important (not programming techniques):
function f = fib(n)
if (n == 1)
f = 1;
elseif (n == 2)
f = 2;
else
fOld = 2;
fOlder = 1;
for i = 3 : n
f = fOld + fOlder;
fOlder = fOld;
fOld = f;
end
end
end
tic;fib(40);toc; ans = 165580141; Elapsed time is 0.000086 seconds.
You could even use uint64. n = 92 is the most you can get from uint64:
tic;fib(92);toc; ans = 12200160415121876738; Elapsed time is 0.001409 seconds.
Because,
fib(93) = 19740274219868223167 > intmax('uint64') = 18446744073709551615
Edit
In order to get fib(n) up to n = 183, It is possible to use two uint64 as one number,
with a special function for summation,
function [] = fib(n)
fL = uint64(0);
fH = uint64(0);
MaxNum = uint64(1e19);
if (n == 1)
fL = 1;
elseif (n == 2)
fL = 2;
else
fOldH = uint64(0);
fOlderH = uint64(0);
fOldL = uint64(2);
fOlderL = uint64(1);
for i = 3 : n
[fL q] = LongSum (fOldL , fOlderL , MaxNum);
fH = fOldH + fOlderH + q;
fOlderL = fOldL;
fOlderH = fOldH;
fOldL = fL;
fOldH = fH;
end
end
sprintf('%u',fH,fL)
end
LongSum is:
function [s q] = LongSum (a, b, MaxNum)
if a + b >= MaxNum
q = 1;
if a >= MaxNum
s = a - MaxNum;
s = s + b;
elseif b >= MaxNum
s = b - MaxNum;
s = s + a;
else
s = MaxNum - a;
s = b - s;
end
else
q = 0;
s = a + b;
end
Note some complications in LongSum might seem unnecessary, but they are not!
(All the deal with inner if is that I wanted to avoid s = a + b - MaxNum in one command, because it might overflow and store an irrelevant number in s)
Results
tic;fib(159);toc; Elapsed time is 0.009631 seconds.
ans = 1226132595394188293000174702095995
tic;fib(183);toc; Elapsed time is 0.009735 seconds.
fib(183) = 127127879743834334146972278486287885163
However, you have to be careful about sprintf.
I also did it with three uint64, and I could get up to,
tic;fib(274);toc; Elapsed time is 0.032249 seconds.
ans = 1324695516964754142521850507284930515811378128425638237225
(It's pretty much the same code, but I could share it if you are interested).
Note that we have fib(1) = 1 , fib(2) = 2according to question, while it is more common with fib(1) = 1 , fib(2) = 1, first 300 fibs are listed here (thanks to #Rick T).

Seems like fibonaacci series follows the golden ratio, as talked about in some detail here.
This was used in this MATLAB File-exchange code and I am writing here, just the esssence of it -
sqrt5 = sqrt(5);
alpha = (1 + sqrt5)/2; %// alpha = 1.618... is the golden ratio
fibs = round( alpha.^n ./ sqrt5 )
You can feed an integer into n for the nth number in Fibonacci Series or feed an array 1:n to have the whole series.
Please note that this method holds good till n = 69 only.

If you have access to the Symbolic Math Toolbox in MATLAB, you could always just call the Fibonacci function from MuPAD:
>> fib = #(n) evalin(symengine, ['numlib::fibonacci(' num2str(n) ')'])
>> fib(274)
ans =
818706854228831001753880637535093596811413714795418360007
It is pretty fast:
>> timeit(#() fib(274))
ans =
0.0011
Plus you can you go for as large numbers as you want (limited only by how much RAM you have!), it is still blazing fast:
% see if you can beat that!
>> tic
>> x = fib(100000);
>> toc % Elapsed time is 0.004621 seconds.
% result has more than 20 thousand digits!
>> length(char(x)) % 20899
Here is the full value of fib(100000): http://pastebin.com/f6KPGKBg

To reach large numbers you can use symbolic computation. The following works in Matlab R2010b.
syms x y %// declare variables
z = x + y; %// define formula
xval = '0'; %// initiallize x, y values
yval = '1';
for n = 2:300
zval = subs(z, [x y], {xval yval}); %// update z value
disp(['Iteration ' num2str(n) ':'])
disp(zval)
xval = yval; %// shift values
yval = zval;
end

You can do it in O(log n) time with matrix exponentiation:
X = [0 1
1 1]
X^n will give you the nth fibonacci number in the lower right-hand corner; X^n can be represented as the product of several matrices X^(2^i), so for example X^11 would be X^1 * X^2 * X^8, i <= log_2(n). And X^8 = (X^4)^2, etc, so at most 2*log(n) matrix multiplications.

One performance issue is that you use a recursive solution. Going for an iterative method will spare you of the argument passing for each function call. As Olivier pointed out, it will reduce the complexity to linear.
You can also look here. Apparently there's a formula that computes the n'th member of the Fibonacci sequence. I tested it for up to 50'th element. For higher n values it's not very accurate.

The implementation of a fast Fibonacci computation in Python could be as follows. I know this is Python not MATLAB/Octave, however it might be helpful.
Basically, rather than calling the same Fibonacci function over and over again with O(2n), we are storing Fibonacci sequence on a list/array with O(n):
#!/usr/bin/env python3.5
class Fib:
def __init__(self,n):
self.n=n
self.fibList=[None]*(self.n+1)
self.populateFibList()
def populateFibList(self):
for i in range(len(self.fibList)):
if i==0:
self.fibList[i]=0
if i==1:
self.fibList[i]=1
if i>1:
self.fibList[i]=self.fibList[i-1]+self.fibList[i-2]
def getFib(self):
print('Fibonacci sequence up to ', self.n, ' is:')
for i in range(len(self.fibList)):
print(i, ' : ', self.fibList[i])
return self.fibList[self.n]
def isNonnegativeInt(value):
try:
if int(value)>=0:#throws an exception if non-convertible to int: returns False
return True
else:
return False
except:
return False
n=input('Please enter a non-negative integer: ')
while isNonnegativeInt(n)==False:
n=input('A non-negative integer is needed: ')
n=int(n) # convert string to int
print('We are using ', n, 'based on what you entered')
print('Fibonacci result is ', Fib(n).getFib())
Output for n=12 would be like:
I tested the runtime for n=100, 300, 1000 and the code is really fast, I don't even have to wait for the output.

One simple way to speed up the recursive implementation of a Fibonacci function is to realize that, substituting f(n-1) by its definition,
f(n) = f(n-1) + f(n-2)
= f(n-2) + f(n-3) + f(n-2)
= 2*f(n-2) + f(n-3)
This simple transformation greatly reduces the number of steps taken to compute a number in the series.
If we start with OP's code, slightly corrected:
function result = fibonacci(n)
switch n
case 0
result = 0;
case 1
result = 1;
case 2
result = 1;
case 3
result = 2;
otherwise
result = fibonacci(n-2) + fibonacci(n-1);
end
And apply our transformation:
function result = fibonacci_fast(n)
switch n
case 0
result = 0;
case 1
result = 1;
case 2
result = 1;
case 3
result = 2;
otherwise
result = fibonacci_fast(n-3) + 2*fibonacci_fast(n-2);
end
Then we see a 30x speed improvement for computing the 20th number in the series (using Octave):
>> tic; for ii=1:100, fibonacci(20); end; toc
Elapsed time is 12.4393 seconds.
>> tic; for ii=1:100, fibonacci_fast(20); end; toc
Elapsed time is 0.448623 seconds.
Of course Rashid's non-recursive implementation is another 60x faster still: 0.00706792 seconds.

Related

MATLAB - Secant method produces NaN

I'm writing a secant method in MATLAB, which I want to iterate through exactly n times.
function y = secantmeth(f,xn_2,xn_1,n)
xn = (xn_2*f(xn_1) - xn_1*f(xn_2))/(f(xn_1) - f(xn_2));
k = 0;
while (k < n)
k = k + 1;
xn_2 = xn_1;
xn_1 = xn;
xn = (xn_2*f(xn_1) - xn_1*f(xn_2))/(f(xn_1) - f(xn_2));
end
y = xn;
end
I believe the method works for small values of n, but even something like n = 9 produces NaN. My guess is that the quantity f(xn_1) - f(xn_2) is approximately zero, which causes this error. How can I prevent this?
Examples:
Input 1
eqn = #(x)(x^2 + x -9)
secantmeth(eqn,2,3,5)
Input 2
eqn = #(x)(x^2 + x - 9)
secantmeth(eqn, 2, 3, 9)
Output 1
2.7321
Output 2
NaN
The value for xn will be NaN when xn_2 and xn_1 are exactly equal, which results in a 0/0 condition. You need to have an additional check in your while loop condition to see if xn_1 and x_n are equal (or, better yet, within some small tolerance of one another), thus suggesting that the loop has converged on a solution and can't iterate any further:
...
while (k < n) && (xn_1 ~= xn)
k = k + 1;
xn_2 = xn_1;
xn_1 = xn;
xn = (xn_2*f(xn_1) - xn_1*f(xn_2))/(f(xn_1) - f(xn_2));
end
...
As Ander mentions in a comment, you could then continue with a different method after your while loop if you want to try and get a more accurate approximation:
...
if (xn_1 == xn) % Previous loop couldn't iterate any further
% Try some new method
end
...
And again, I would suggest reading through this question to understand some of the pitfalls of floating-point comparison (i.e. == and ~= aren't usually the best operators to use for floating-point numbers).

vectorizing function in octave / matlab

I have a function that I was wondering if it was possible to vectorize it and not have to use a for loop. The code is below.
a=1:2:8
for jj=1:length(a)
b(jj)=rtfib(a(jj)); %fibbonacci function
end
b
output below:
a =
1 3 5 7
>>>b =
1 3 8 21
I was trying to do it this way
t = 0:.01:10;
y = sin(t);
but doing the code below doesn't work any suggestions?
ps: I'm trying to keep the function rtfib because of it's speed and I need to use very large Fibonacci numbers. I'm using octave 3.8.1
a=1:2:8
b=rtfib(a)
Here's the rtfib code below as requested
function f = rtfib(n)
if (n == 0)
f = 0;
elseif (n==1)
f=1;
elseif (n == 2)
f = 2;
else
fOld = 2;
fOlder = 1;
for i = 3 : n
f = fOld + fOlder;
fOlder = fOld;
fOld = f;
end
end
end
You can see that your function rtfib actually computes every Fibonacci number up to n.
You can modify it so that is stores and returns all these number, so that you only have to call the function once with the maximum number you need:
function f = rtfib(n)
f=zeros(1,n+1);
if (n >= 0)
f(1) = 0;
end
if (n>=1)
f(2)=1;
end
if (n >= 2)
f(3) = 2;
end
if n>2
fOld = 2;
fOlder = 1;
for i = 3 : n
f(i+1) = fOld + fOlder;
fOlder = fOld;
fOld = f(i+1);
end
end
end
(It will return fibonnaci(n) in f(n+1), if you don't need the 0 you could change it so that it returns fibonnaci(n) in f(n) if you prefer)
Then you only need to call
>>f=rtfib(max(a));
>>b=f(a+1)
b =
1 3 8 21
If you don't want to store everything you could modify the function rtfib a little more, so that it takes the the array a as input, compute the Fibonacci numbers up to max(a) but only stores the one needed, and it would directly return b.
Both solutions will slow down rtfib itself but it will be a lot faster than calculating the Fibonacci numbers from 0 each time.

MATLAB sum series function

I am very new in Matlab. I just try to implement sum of series 1+x+x^2/2!+x^3/3!..... . But I could not find out how to do it. So far I did just sum of numbers. Help please.
for ii = 1:length(a)
sum_a = sum_a + a(ii)
sum_a
end
n = 0 : 10; % elements of the series
x = 2; % value of x
s = sum(x .^ n ./ factorial(n)); % sum
The second part of your answer is:
n = 0:input('variable?')
Cheery's approach is perfectly valid when the number of terms of the series is small. For large values, a faster approach is as follows. This is more efficient because it avoids repeating multiplications:
m = 10;
x = 2;
result = 1+sum(cumprod(x./[1:m]));
Example running time for m = 1000; x = 1;
tic
for k = 1:1e4
result = 1+sum(cumprod(x./[1:m]));
end
toc
tic
for k = 1:1e4
result = sum(x.^(0:m)./factorial(0:m));
end
toc
gives
Elapsed time is 1.572464 seconds.
Elapsed time is 2.999566 seconds.

Factorization of an integer

While answering another, I stumbled over the question how I actually could find all factors of an integer number without the Symbolic Math Toolbox.
For example:
factor(60)
returns:
2 2 3 5
unique(factor(60))
would therefore return all prime-factors, "1" missing.
2 3 5
And I'm looking for a function which would return all factors (1 and the number itself are not important, but they would be nice)
Intended output for x = 60:
1 2 3 4 5 6 10 12 15 20 30 60
I came up with that rather bulky solution, apart from that it probably could be vectorized, isn't there any elegant solution?
x = 60;
P = perms(factor(x));
[n,m] = size(P);
Q = zeros(n,m);
for ii = 1:n
for jj = 1:m
Q(ii,jj) = prod(P(ii,1:jj));
end
end
factors = unique(Q(:))'
Also I think, this solution will fail for certain big numbers, because perms requires a vector length < 11.
You can find all factors of a number n by dividing it by a vector containing the integers 1 through n, then finding where the remainder after division by 1 is exactly zero (i.e., the integer results):
>> n = 60;
>> find(rem(n./(1:n), 1) == 0)
ans =
1 2 3 4 5 6 10 12 15 20 30 60
Here is a comparison of six different implementations for finding factors of an integer:
function [t,v] = testFactors()
% integer to factor
%{45, 60, 2059, 3135, 223092870, 3491888400};
n = 2*2*2*2*3*3*3*5*5*7*11*13*17*19;
% functions to compare
fcns = {
#() factors1(n);
#() factors2(n);
#() factors3(n);
#() factors4(n);
%#() factors5(n);
#() factors6(n);
};
% timeit
t = cellfun(#timeit, fcns);
% check results
v = cellfun(#feval, fcns, 'UniformOutput',false);
assert(isequal(v{:}));
end
function f = factors1(n)
% vectorized implementation of factors2()
f = find(rem(n, 1:floor(sqrt(n))) == 0);
f = unique([1, n, f, fix(n./f)]);
end
function f = factors2(n)
% factors come in pairs, the smaller of which is no bigger than sqrt(n)
f = [1, n];
for k=2:floor(sqrt(n))
if rem(n,k) == 0
f(end+1) = k;
f(end+1) = fix(n/k);
end
end
f = unique(f);
end
function f = factors3(n)
% Get prime factors, and compute products of all possible subsets of size>1
pf = factor(n);
f = arrayfun(#(k) prod(nchoosek(pf,k),2), 2:numel(pf), ...
'UniformOutput',false);
f = unique([1; pf(:); vertcat(f{:})])'; %'
end
function f = factors4(n)
% http://rosettacode.org/wiki/Factors_of_an_integer#MATLAB_.2F_Octave
pf = factor(n); % prime decomposition
K = dec2bin(0:2^length(pf)-1)-'0'; % all possible permutations
f = ones(1,2^length(pf));
for k=1:size(K)
f(k) = prod(pf(~K(k,:))); % compute products
end;
f = unique(f); % eliminate duplicates
end
function f = factors5(n)
% #LuisMendo: brute-force implementation
f = find(rem(n, 1:n) == 0);
end
function f = factors6(n)
% Symbolic Math Toolbox
f = double(evalin(symengine, sprintf('numlib::divisors(%d)',n)));
end
The results:
>> [t,v] = testFactors();
>> t
t =
0.0019 % factors1()
0.0055 % factors2()
0.0102 % factors3()
0.0756 % factors4()
0.1314 % factors6()
>> numel(v{1})
ans =
1920
Although the first vectorized version is the fastest, the equivalent loop-based implementation (factors2) is not far behind, thanks to automatic JIT optimization.
Note that I had to disable the brute-force implementation (factors5()) because it throws an out-of-memory error (storing the vector 1:3491888400 in double-precision requires over 26GB of memory!). This method is obviously not feasible for large integers, neither space- or time-wise.
Conclusion: use the following vectorized implementation :)
n = 3491888400;
f = find(rem(n, 1:floor(sqrt(n))) == 0);
f = unique([1, n, f, fix(n./f)]);
An improvement over #gnovice's answer is to skip the division operation: rem alone is enough:
n = 60;
find(rem(n, 1:n)==0)

optimizing nested for loop in matlab

I'm trying to optimize the performance (e.g. speed) of my code. I 'm new to vectorization and tried myself to vectorize, but unsucessful ( also try bxsfun, parfor, some kind of vectorization, etc ). Can anyone help me optimize this code, and a short description of how to do this?
% for simplify, create dummy data
Z = rand(250,1)
z1 = rand(100,100)
z2 = rand(100,100)
%update missing param on the last updated, thanks #Bas Swinckels and #Daniel R
j = 2;
n = length(Z);
h = 0.4;
tic
[K1, K2] = size(z1);
result = zeros(K1,K2);
for l = 1 : K1
for m = 1: K2
result(l,m) = sum(K_h(h, z1(l,m), Z(j+1:n)).*K_h(h, z2(l,m), Z(1:n-j)));
end
end
result = result ./ (n-j);
toc
The K_h.m function is the boundary kernel and defined as (x is scalar and y can be vector)
function res = K_h(h, x,y)
res = 0;
if ( x >= 0 & x < h)
denominator = integral(#kernelFunc,-x./h,1);
res = 1./h.*kernelFunc((x-y)/h)/denominator;
elseif (x>=h & x <= 1-h)
res = 1./h*kernelFunc((x-y)/h);
elseif (x > 1 - h & x <= 1)
denominator = integral(#kernelFunc,-1,(1-x)./h);
res = 1./h.*kernelFunc((x-y)/h)/denominator;
else
fprintf('x is out of [0,1]');
return;
end
end
It takes a long time to obtain the results: \Elapsed time is 13.616413 seconds.
Thank you. Any comments are welcome.
P/S: Sorry for my lack of English
Some observations: it seems that Z(j+1:n)) and Z(1:n-j) are constant inside the loop, so do the indexing operation before the loop. Next, it seems that the loop is really simple, every result(l, m) depends on z1(l, m) and z2(l, m). This is an ideal case for the use of arrayfun. A solution might look something like this (untested):
tic
% do constant stuff outside of the loop
Zhigh = Z(j+1:n);
Zlow = Z(1:n-j);
result = arrayfun(#(zz1, zz2) sum(K_h(h, zz1, Zhigh).*K_h(h, zz2, Zlow)), z1, z2)
result = result ./ (n-j);
toc
I am not sure if this will be a lot faster, since I guess the running time will not be dominated by the for-loops, but by all the work done inside the K_h function.