-module(mmath_comb). -include("mmath.hrl"). -ifdef(TEST). -compile(export_all). -endif. -export([avg/1, avg_r/1, sum/1, sum_r/1, mul/1, merge/1, zip/2]). -define(APPNAME, mmath). -define(LIBNAME, comb_nif). -on_load(load_nif/0). load_nif() -> SoName = case code:priv_dir(?APPNAME) of {error, bad_name} -> case filelib:is_dir(filename:join(["..", priv])) of true -> filename:join(["..", priv, ?LIBNAME]); _ -> filename:join([priv, ?LIBNAME]) end; Dir -> filename:join(Dir, ?LIBNAME) end, erlang:load_nif(SoName, 0). sum_r([A, B]) -> sum_r(A, B); sum_r([A, B, C]) -> sum_r(A, B, C); sum_r(Es) -> rcomb(fun sum_r/2, fun sum_r/3, Es, []). sum_r(A, B) -> mmath_bin:realize(sum(mmath_bin:derealize(A), mmath_bin:derealize(B))). sum_r(A, B, C) -> mmath_bin:realize(sum(mmath_bin:derealize(A), mmath_bin:derealize(B), mmath_bin:derealize(C))). sum([A, B]) -> sum(A, B); sum([A, B, C]) -> sum(A, B, C); sum(Es) -> rcomb(fun sum/2, fun sum/3, Es, []). avg_r(Es) -> mmath_aggr:divide_r(sum_r(Es), length(Es)). avg(Es) -> mmath_aggr:divide(sum(Es), length(Es)). merge(Es) -> rcomb(fun merge/2, Es, []). sum(A, B) -> sum(A, B, 0, 0, <<>>). sum(A, B, C) -> sum(A, sum(B, C)). %% Optimistic case that will combine 10 values of data at once. sum(<>, <>, _LA, _LB, Acc) -> Acc1 = <>, sum(RA, RB, A9, B9, Acc1); sum(<<>>, <<>>, _LA, _LB, Acc) -> Acc; sum(<>, <<>>, _LA, LB, Acc) -> sum(RA, <<>>, A, LB, <>); sum(<>, <<>>, LA, LB, Acc) -> sum(RA, <<>>, LA, LB, <>); sum(<<>>, <>, LA, _LB, Acc) -> sum(<<>>, RB, LA, B, <>); sum(<<>>, <>, LA, LB, Acc) -> sum(<<>>, RB, LA, LB, <>); sum(<>, <>, _LA, _LB, Acc) -> sum(RA, RB, A, B, <>); sum(<>, <>, _LA, LB, Acc) -> sum(RA, RB, A, LB, <>); sum(<>, <>, LA, _LB, Acc) -> sum(RA, RB, LA, B, <>); sum(<>, <>, LA, LB, Acc) -> sum(RA, RB, LA, LB, <>). mul(Es) -> rcomb(fun mul/2, Es, []). mul(A,B) -> mul(A, B, 1, 1, <<>>). mul(<<>>, <<>>, _LA, _LB, Acc) -> Acc; mul(<>, <>, _LA, _LB, Acc) -> mul(RA, RB, A, B, <>); mul(<>, <>, _LA, LB, Acc) -> mul(RA, RB, A, LB, <>); mul(<>, <>, LA, _LB, Acc) -> mul(RA, RB, LA, B, <>); mul(<>, <>, LA, LB, Acc) -> mul(RA, RB, LA, LB, <>). zip(Fn, Es) -> rcomb(fun (A, B) -> zip(Fn, A, B) end, Es, []). zip(Fn, A, B) -> zip(A, B, 1, 1, Fn, <<>>). zip(<<>>, <<>>, _LA, _LB, _Fn, Acc) -> Acc; zip(<>, <>, _LA, _LB, Fn, Acc) -> zip(RA, RB, A, B, Fn, apply(Fn, A, B, Acc)); zip(<>, <>, _LA, LB, Fn, Acc) -> zip(RA, RB, A, LB, Fn, apply(Fn, A, LB, Acc)); zip(<>, <>, LA, _LB, Fn, Acc) -> zip(RA, RB, LA, B, Fn, apply(Fn, LA, B, Acc)); zip(<>, <>, LA, LB, Fn, Acc) -> zip(RA, RB, LA, LB, Fn, apply(Fn, LA, LB, Acc)). apply(Fn, A, B, Acc) -> case Fn(A, B) of V when is_integer(V) -> <>; V when is_float(V) -> <> end. merge(A, B) -> merge(A, B, <<>>). merge(<>, <>, Acc) -> merge(R1, R2, <>); merge(<>, <<_:?DATA_SIZE/binary, R2/binary>>, Acc) -> merge(R1, R2, <>); merge(<<>>, <<>>, Acc) -> Acc; merge(<<>>, D, Acc) -> <>; merge(D, <<>>, Acc) -> <>. rcomb(F2, In, Acc) -> rcomb(F2, undefined, In, Acc). rcomb(F2, _F3, [A], [B]) -> F2(A, B); rcomb(F2, F3, [], Acc) -> rcomb(F2, F3, Acc, []); rcomb(_, _, [A], []) -> A; rcomb(F2, F3, [A, B, C, D | R], Acc) -> rcomb(F2, F3, R, [F2(F2(A, B), F2(C, D)) | Acc]); rcomb(F2, F3, [A, B, C | R], Acc) when is_function(F3) -> rcomb(F2, F3, R, [F3(A, B, C) | Acc]); rcomb(F2, F3, [A, B | R], Acc) -> rcomb(F2, F3, R, [F2(A, B) | Acc]); rcomb(F2, F3, [A], Acc) -> rcomb(F2, F3, [A | Acc], []).