Skip to content

Instantly share code, notes, and snippets.

@pichi
Last active March 5, 2017 21:25
Show Gist options
  • Save pichi/8238258 to your computer and use it in GitHub Desktop.
Save pichi/8238258 to your computer and use it in GitHub Desktop.
Big Fibonacci number generator in Erlang
%% Fibonacci number generator in Erlang
%% by Hynek Vychodil <[email protected]> 3-JAN-2014
%% Distributed under MIT license at the end of the source code.
-module(fib).
-export([fib/1]).
% NOTE: Native compilation (HiPE) doesn't improve efficiency due heavy integer
% bignum computations as observed in R16
% Empirical limit for using linear algorithm
-define(LIN_LIM, 100).
-spec fib(integer()) -> integer().
fib(0) -> 0;
fib(1) -> 1;
fib(2) -> 1;
fib(3) -> 2;
fib(4) -> 3;
fib(5) -> 5;
fib(N) when is_integer(N), N < 0 ->
% extension to negative values
if N rem 2 =:= 0 ->
-fib(-N);
true ->
fib(-N)
end;
fib(N) when is_integer(N) ->
if N < ?LIN_LIM -> % use linear algorithm
fib(N - 6, 5, 8);
true -> % use matrix exponentiation
fib(N - 1, 1, 1, 0, 1, 0, 1)
end.
% linear algorithm
fib(N, A, B) -> if N < 1 -> B; true -> fib(N-1, B, A+B) end.
% matrix exponentiation
%
% n-1
% ⎛ 1 1 ⎞ ⎛ F(n) F(n-1) ⎞
% ⎜ ⎟ = ⎜ ⎟
% ⎝ 1 0 ⎠ ⎝ F(n-1) F(n-2) ⎠
%
% Each matrix is symmetric so store only upper triangle
% X, Y, Z is initial matrix - base for exponentiation
% A, B, C is accumulated result - initiated with identity matrix
fib(0, _, _, _, A, _, _) -> A;
fib(N, X, Y, Z, A, B, C) ->
if N rem 2 =:= 1 ->
XA = X*A,
XB = X*B,
YB = Y*B,
YC = Y*C,
ZC = Z*C,
fib(N - 1, X, Y, Z, XA + YB, XB + YC, YB + ZC);
true ->
XX = X*X,
XY = X*Y,
YY = Y*Y,
YZ = Y*Z,
ZZ = Z*Z,
fib(N div 2, XX + YY, XY + YZ, YY + ZZ, A, B, C)
end.
%% MIT License:
%% Copyright (c) 2014 by Hynek Vychodil.
%%
%% Permission is hereby granted, free of charge, to any person
%% obtaining a copy of this software and associated documentation
%% files (the "Software"), to deal in the Software without
%% restriction, including without limitation the rights to use,
%% copy, modify, merge, publish, distribute, sublicense, and/or sell
%% copies of the Software, and to permit persons to whom the
%% Software is furnished to do so, subject to the following
%% conditions:
%%
%% The above copyright notice and this permission notice shall be
%% included in all copies or substantial portions of the Software.
%%
%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
%% EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
%% OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
%% NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
%% HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
%% WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
%% FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
%% OTHER DEALINGS IN THE SOFTWARE.
@T-xy
Copy link

T-xy commented Apr 26, 2014

Dijkstra algorithm seems a tiny bit faster than matrix exponentiation
http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/fibFormula.html
a very basic implementation (especially the n-th bit extraction (X>1) is nasty):

-module(fib2).
-export([fib/1]).
-spec fib(float()) -> integer().

fib(0) -> 0;
fib(1) -> 1;
fib(N) -> fibi(2 * (pos(N * 2 + 1) - 1), 0, 1).

pos(D) ->
    if D < 2 -> D;
    true -> pos(D/2)
end.

fibi(X, A, B) ->        
    if(X == 0.5)-> (A+A+B)*B;
      (X == 1 ) -> B;
      (X >  1 ) -> 
        AA = A*A+B*B,
        BB = (A+A+B)*B,
        fibi(2 * (X-1), BB, AA+BB);
          true -> 
        AA = A*A+B*B,
        BB = (A+A+B)*B,
        fibi(2 * X, AA, BB)
    end.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment