anchor.diff:  
   -include("edis.hrl").
   
  +-record(symbols, {up_up     = $" :: char(),
  +                  up_down   = $= :: char(),
  +                  up_none   = $^ :: char(),
  +                  none_up   = $ :: char(),
  +                  none_down = $_ :: char(),
  +                  none_none = $\s:: char(),
  +                  down_up   = $+ :: char(),
  +                  down_down = $. :: char(),
  +                  down_none = $, :: char()}).
  +
   -type option() :: {start, pos_integer} | {step, pos_integer()} | {rounds, pos_integer()} |
           {extra_args, [term()]} | {outliers, pos_integer()} | {columns, pos_integer()} |
           {first_col, pos_integer()} | {rows, pos_integer()} | debug | {k, number()} | {x, number()}.
   -export_type([option/0]).
   
  --export([compare/4, compare/3,
  -         graph/4, graph/3, graph/2,
  -         run/3, run/2, run/1,
  -         behaviour_info/1]).
  +-export([bench/4, bench/3, bench/2, behaviour_info/1]).
   
   -export([zero/1, constant/1, linear/1, quadratic/1, logarithmic/1, xlogarithmic/1, exponential/1]).
   
  
positive.code:       try Module:quit() catch _:undef -> ok end
    end.
  
  %% @doc Compares the different runs of Module:Function to a given function.
  %%      Returns the standard deviation of the distances between them (outliers excluded).
  %%      The higher the value the more different functions are.
  -spec compare(atom(), atom(), atom() | fun((pos_integer()) -> number()), [option()]) -> float().
  compare(Module, Function, MathFunction, Options) when is_atom(MathFunction) ->
    compare(Module, Function, fun(X) -> ?MODULE:MathFunction(X) end, Options);
  compare(Module, Function, MathFunction, Options) ->
    RawResults = run(Module, Function, Options),
    Distances =
      [case {V, proplists:get_value(x, Options, 0) +
               (proplists:get_value(k, Options, 1) * MathFunction(K))} of
         {error, _} -> 0;
         {_, 0} -> 0;
         {V, M} -> M / V
       end || {K, V} <- RawResults],
    WithoutOutliers =
      lists:sublist(
        lists:sort(Distances), 1,
        proplists:get_value(rounds, Options, 250) - 2 * proplists:get_value(outliers, Options, 20)),
    Avg = lists:sum(WithoutOutliers) / length(WithoutOutliers),
    case proplists:get_bool(debug, Options) of
      true -> ?INFO("~p~n", [lists:sort(Distances)]);
      false -> ok
    end,
    do_graph(RawResults, MathFunction, Options),
    lists:sum([case Distance of
                 Distance when Distance >= Avg -> Distance - Avg;
                 _ -> Avg - Distance
               end || Distance <- Distances]) / length(Distances).
  %% math:sqrt([(Distance - Avg) * (Distance - Avg) / Avg || Distance <- Distances])).
  
  %% @doc Compares the different runs of Module:Function/1 to a given function.
  %% @equiv compare(Module, Function, [])
  -spec compare(atom(), atom(), atom() | fun((pos_integer()) -> number())) -> float().
  compare(Module, Function, MathFunction) ->
    compare(Module, Function, MathFunction, []).
  
  %% @doc Graphs the results of running Module:Function/1 using ASCII Art
  %% @equiv graph(Module, Function, [])
  -spec graph(atom(), atom()) -> ok.
  graph(Module, Function) ->
    graph(Module, Function, []).
  
  %% @doc Graphs the results of running Module:Function using ASCII Art
  %% @equiv graph(Module, Function, zero, Options)
  -spec graph(atom(), atom(), [option()]) -> ok.
  graph(Module, Function, Options) ->
    graph(Module, Function, zero, Options).
  
  %% @doc Graphs the results of running Module:Function using ASCII Art
  -spec graph(atom(), atom(), atom() | fun((pos_integer()) -> number()), [option()]) -> ok.
  graph(Module, Function, MathFunction, Options) when is_atom(MathFunction) ->
    graph(Module, Function, fun(X) -> ?MODULE:MathFunction(X) end, Options);
  graph(Module, Function, MathFunction, Options) ->
    do_graph(run(Module, Function, Options), MathFunction, Options).
  
  %% ====================================================================
  %% Math functions
  %% ====================================================================
  %% @doc O(1) comparer
  -spec zero(pos_integer()) -> pos_integer().
  zero(_) -> 0.
  
  %% @doc O(1) comparer
  -spec constant(pos_integer()) -> pos_integer().
  constant(_) -> 1.
  
  %% @doc O(n) comparer
  -spec linear(pos_integer()) -> pos_integer().
  linear(N) -> N.
  
  %% @doc O(n^2) comparer
  -spec quadratic(pos_integer()) -> pos_integer().
  quadratic(N) -> N * N.
  
  %% @doc O(log(n)) comparer
  -spec logarithmic(pos_integer()) -> float().
  logarithmic(N) -> math:log(N) + 1.
  
  %% @doc O(n*log(n)) comparer
  -spec xlogarithmic(pos_integer()) -> float().
  xlogarithmic(N) -> N * math:log(N) + 1.
  
  %% @doc O(e^n) comparer
  -spec exponential(pos_integer()) -> float().
  exponential(N) -> math:pow(2.71828182845904523536028747135266249775724709369995, N).
  
  %% ====================================================================
  %% Internal functions
  %% ====================================================================
  do_run(Module, Function, Options) ->
    ok = try Module:init_per_testcase(Function) catch _:undef -> ok end,
    Start = proplists:get_value(start, Options, 1),
    try lists:map(fun(N) -> do_run(Module, Function, N, Options) end,
          lists:seq(
                    Start,
                    Start +proplists:get_value(rounds, Options, 250) *
                      proplists:get_value(step, Options, 1),
                    proplists:get_value(step, Options, 1)))
    after
  
negative.code:       try Module:quit_per_round(Function, Items) catch _:undef -> ok end
    end.
  
  graph(Results, Options) ->
    RawData = lists:sublist(Results,
                            proplists:get_value(first_col, Options, 1),
                            erlang:min(proplists:get_value(columns, Options, 250),
                                       proplists:get_value(rounds, Options, 250))),
    SortedData = lists:keysort(2, [{K, V, M} || {K, V, M} <- RawData, V =/= error, M =/= error]),
    Outliers =
      [{K, error, M} || {K, error, M} <- RawData] ++ [{K, V, error} || {K, V, error} <- RawData] ++
        lists:sublist(lists:reverse(SortedData), 1, proplists:get_value(outliers, Options, 20)),
    Data =
      [case lists:member({K,V,M}, Outliers) of
         true -> {K, 0, M};
         false -> {K, V, M}
       end || {K,V,M} <- Results],
    Top = lists:max([erlang:max(V, M) || {_, V, M} <- Data]),
    Bottom = erlang:trunc(lists:min([erlang:min(V, M) || {_, V, M} <- Data, V > 0, M > 0]) / 2),
    Step = (Top - Bottom) / proplists:get_value(rows, Options, 70),
    io:format("8"),
    graph(Top, Bottom, Step, proplists:get_value(symbols, Options, #symbols{}), Data).
  
  graph(Top, Bottom, _Step, _Symbols, Data) when Top =< Bottom ->
    io:format("       ~s~n", [lists:duplicate(length(Data), $-)]),
    io:format("       ~s~n", [lists:map(fun({K, _, _}) -> integer_to_list(K rem 10) end, Data)]);
  graph(Top, Bottom, Step, Symbols, Data) ->
    io:format("~7.2.0f~s~n",
              [Top * 1.0,
               lists:map(
                 fun({_, V, M}) when Top >= V, V > Top - Step,
                                     Top >= M, M > Top - Step ->
                         case {Top - V, Top - M} of
                           {Pos, Mos} when Pos < Step/2, Mos < Step/2 -> Symbols#symbols.up_up;
                           {Pos, Mos} when Pos < Step/2, Mos >= Step/2 -> Symbols#symbols.up_down;
                           {Pos, Mos} when Pos >= Step/2, Mos < Step/2 -> Symbols#symbols.down_up;
                           {Pos, Mos} when Pos >= Step/2, Mos >= Step/2 -> Symbols#symbols.down_down
                         end;
                    ({_, V, _M}) when Top >= V, V > Top - Step ->
                         case Top - V of
                           Pos when Pos < Step/2 -> Symbols#symbols.up_none;
                           Pos when Pos >= Step/2 -> Symbols#symbols.down_none
                         end;
                    ({_, _V, M}) when Top >= M, M > Top - Step ->
                         case Top - M of
                           Pos when Pos < Step/2 -> Symbols#symbols.none_up;
                           Pos when Pos >= Step/2 -> Symbols#symbols.none_down
                         end;
                    (_) -> Symbols#symbols.none_none
                 end, Data)]),
    graph(Top-Step, Bottom, Step, Symbols, Data).