RosettaCodeData/Task/Four-bit-adder/Erlang/four-bit-adder.erl

71 lines
2.0 KiB
Erlang

-module( four_bit_adder ).
-export( [add_bits/3, create/1, task/0] ).
add_bits( Adder, A_bits, B_bits ) ->
Adder ! {erlang:self(), lists:reverse(A_bits), lists:reverse(B_bits)},
receive
{Adder, Sum, Carry} -> {Sum, Carry}
end.
create( How_many_bits ) ->
Full_adders = connect_full_adders( [full_adder_create() || _X <- lists:seq(1, How_many_bits)] ),
erlang:spawn_link( fun() -> bit_adder_loop( Full_adders ) end ).
task() ->
Adder = create( 4 ),
add_bits( Adder, [0,0,1,0], [0,0,1,1] ).
bit_adder_loop( Full_adders ) ->
receive
{Pid, As, Bs} ->
Sum = [full_adder_sum(Adder, A, B) || {Adder, A, B} <- lists:zip3(Full_adders, As, Bs)],
Carry = receive
{carry, C} -> C
end,
Pid ! {erlang:self(), lists:reverse(Sum), Carry},
bit_adder_loop( Full_adders )
end.
connect_full_adders( [Full_adder | T]=Full_adders ) ->
lists:foldl( fun connect_full_adders/2, Full_adder, T ),
Full_adders.
connect_full_adders( Full_adder, Previous_full_adder ) ->
Previous_full_adder ! {carry_to, Full_adder},
Full_adder.
half_adder( A, B ) -> {z_xor(A, B), A band B}.
full_adder( A, B, Carry ) ->
{Sum1, Carry1} = half_adder( A, Carry),
{Sum, Carry2} = half_adder( B, Sum1),
{Sum, Carry1 bor Carry2}.
full_adder_create( ) -> erlang:spawn( fun() -> full_adder_loop({0, no_carry_pid}) end ).
full_adder_loop( {Carry, Carry_to} ) ->
receive
{carry, New_carry} -> full_adder_loop( {New_carry, Carry_to} );
{carry_to, Pid} -> full_adder_loop( {Carry, Pid} );
{add, Pid, A, B} ->
{Sum, New_carry} = full_adder( A, B, Carry ),
Pid ! {sum, erlang:self(), Sum},
full_adder_loop_carry_pid( Carry_to, Pid ) ! {carry, New_carry},
full_adder_loop( {New_carry, Carry_to} )
end.
full_adder_loop_carry_pid( no_carry_pid, Pid ) -> Pid;
full_adder_loop_carry_pid( Pid, _Pid ) -> Pid.
full_adder_sum( Pid, A, B ) ->
Pid ! {add, erlang:self(), A, B},
receive
{sum, Pid, S} -> S
end.
%% xor exists, this is another implementation.
z_xor( A, B ) -> (A band (2+bnot B)) bor ((2+bnot A) band B).