Skip to content

Instantly share code, notes, and snippets.

@ashleyholman
Created August 1, 2013 01:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ashleyholman/6127853 to your computer and use it in GitHub Desktop.
Save ashleyholman/6127853 to your computer and use it in GitHub Desktop.
This is some code I wrote when I was playing around with Erlang and trying to learn it. I decided to tackle a problem of calculating factorials. As in, fac(n) is the product of n * (n-1) * ... * 2 * 1. For n < 1000, the code does this one a single core using the "condense terms" loop, which simply multiplies pairs of numbers together, and then r…
-module(fac).
-export([fac/1, multiply_terms/1, condense_terms/1, shuffle/1, fac_multi_actor/3]).
% when N >= 1000, partition into 3 sublists and distribute work amongst 3 processes
fac(N) when N >= 1000 ->
L = shuffle(lists:seq(1, N)),
D = trunc(N / 3),
FirstPart = lists:sublist(L, 1, D),
SecondPart = lists:sublist(L, D, D),
LastPart = lists:sublist(L, D*2, N),
Sublists = [FirstPart, SecondPart, LastPart],
fac_multi_spawn(Sublists),
fac_multi_collect(length(Sublists));
fac(N) -> multiply_terms(lists:seq(1, N)).
fac_multi_spawn(Ls) -> fac_multi_spawn(Ls, 1).
fac_multi_spawn([], _) -> true;
fac_multi_spawn([HL | TL], Count) ->
spawn(fac, fac_multi_actor, [self(), HL, Count]),
io:format("spawned ~B~n", [Count]),
fac_multi_spawn(TL, Count+1).
fac_multi_actor(Caller, L, Num) ->
Answer = multiply_terms(L),
Caller ! {Num, Answer},
io:format("finished work in ~B with ~s~n", [Num, Answer =:= 1]).
fac_multi_collect(N) -> fac_multi_collect(N, 1).
fac_multi_collect(0, Acc) ->
io:format("got zero!~n"),
Acc;
fac_multi_collect(N, Acc) ->
io:format("yodle~n"),
receive
{Num, Product} ->
Ret = fac_multi_collect(N-1, Product*Acc),
io:format("return from collect ~B~n", [Num]),
Ret
end.
multiply_terms([H]) -> H;
multiply_terms(L) ->
multiply_terms(condense_terms(L)). % tail recursive
% condense_terms([1, 2, 3, 4, 5, 6, 7] = [7, 30, 12, 3]
condense_terms(L) -> condense_terms(L, []).
condense_terms([], Acc) -> shuffle(Acc);
condense_terms([A], Acc) -> [A|Acc];
condense_terms([A, B | T], Acc) ->
condense_terms(T, [A * B | Acc]).
% shuffle so that [1, 2, 3, 4, 5] -> [1, 5, 2, 4, 3]
shuffle(L) ->
{FirstHalf, LastHalf} = lists:split(trunc(length(L)/2), L),
shuffle_merge(FirstHalf, lists:reverse(LastHalf)).
shuffle_merge(L1, L2) ->
lists:reverse(shuffle_merge(L1, L2, [])).
shuffle_merge([], [], Acc) -> Acc;
shuffle_merge([], [L2], Acc) -> [L2|Acc];
shuffle_merge([H1|T1], [H2|T2], Acc) -> shuffle_merge(T1, T2, [H2, H1|Acc]).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment