koko
koko

Reputation: 17

multiplication of two list using list -erlang

how to multiple two numbers represented in a list for example 123 * 12 = 1476 I want to do this operation using list in this example it should be like this mul([1,2,3],[1,2]) result will be [1,4,7,6] without converting list to number by using list_to_integer function. I did this so far but its just working if the length of one of the list is equal to one

mul([],A) ->[];
mul(A,[]) ->[];
mul([H|T],B) -> 
             if

    (length([H|T]) ==1) or (length(B)== 1)
                                        ->
                                        [X*Y||X<-[H],Y<-B]++mul(T,B);



        (length([H|T]) >1) or (length(B) > 1)                               

                                            -> 
                                             [X*Y||X<-[H],Y<-B]++mul(T,B)

     end.

Upvotes: 1

Views: 462

Answers (3)

7stud
7stud

Reputation: 48629

Here's a version that allows you to specify a base (2-10):

In the shell:

167> c(my).                                    
{ok,my}

168> Base10 = 10.                              
10
169> Base2 = 2.
2

170> my:list_mult([1,1], [1,1,1], Base10).       
[1,2,2,1]
171> 11 * 111.                            
1221


172>  my:list_mult([1,1], [1,1,1], Base2). 
[1,0,1,0,1]
173> io:format("~.2B~n", [2#11 * 2#111]).       
10101
ok

-module(my).
%%-compile(export_all).
-export([list_mult/3]).
-include_lib("eunit/include/eunit.hrl").

list_mult(List1, List2, Base) ->
    Number = digits_to_int(List1, Base) * digits_to_int(List2, Base),
    list_of_digits(Number, Base).

list_mult_test() ->
    Base10 = 10,
    ?assertEqual( 
        list_of_digits(123 * 12, Base10), 
        list_mult([1,2,3], [1,2], Base10)
    ),
    ?assertEqual(
        list_of_digits(2 * 5, Base10),
        list_mult([2], [5], Base10)
    ),
    ?assertEqual(
        list_of_digits(0 * 0, Base10),
        list_mult([], [], Base10)
    ),
    ?assertEqual(
        list_of_digits(0 * 23, Base10),
        list_mult([], [2,3], Base10)
    ),
    ?assertEqual(
        list_of_digits(30 * 4, Base10),
        list_mult([0,3,0], [0,4], Base10)
    ),
    ?assertEqual(
        list_of_digits(1 * 3, Base10), 
        list_mult([0,0,1], [0,3], Base10)
    ),

    Base2 = 2,
    ?assertEqual(
        list_of_digits(2#11 * 2#1000, Base2), 
        list_mult([1,1], [1,0,0,0], Base2)
    ),
    ?assertEqual(
        list_of_digits(2#1001 * 2#10, Base2),
        list_mult([1,0,0,1], [1,0], Base2)
    ),

    %%Errors:
    ?assertThrow(
       "illegal_number: Some elements are >= to Base",
       list_mult([1,3], [1,0,0,0,0], Base2)
    ),
    ?assertThrow(
       "illegal_number: Some elements are >= to Base",
       list_mult([a, 3], [f,1], Base10)  %%hex notation
    ).    

%--------------

digits_to_int_test() ->
    Base10 = 10,
    ?assertEqual(
       123,
       digits_to_int([1,2,3], Base10)
    ),
    ?assertEqual(
       10,
       digits_to_int([1,0], Base10)
    ),
    ?assertEqual(
       3,
       digits_to_int([3], Base10)
    ),
    ?assertEqual(
       0,
       digits_to_int([0], Base10)
    ),
    ?assertEqual(
       0,
       digits_to_int([], Base10)
    ),

    Base2 = 2,
    ?assertEqual(
       2#11,
       digits_to_int([1,1], Base2)
    ),
    ?assertEqual(
       2#1101,
       digits_to_int([1,1,0,1], Base2)
    ),
    ?assertEqual(
       2#11110000,
       digits_to_int([1,1,1,1, 0,0,0,0], Base2)
    ),
    ?assertEqual(
       2#1,
       digits_to_int([1], Base2)
    ),
    ?assertEqual(
       0,
       digits_to_int([0], Base2)
    ),
    ?assertEqual(
       0,
       digits_to_int([], Base2)
    ),
    %%Errors:
    ?assertThrow(
       "illegal_number: Some elements are >= to Base",
       digits_to_int([1,2,3], Base2)
    ),
    ?assertThrow(
       "illegal_number: Some elements are >= to Base",
       list_mult([a, 3], [f,1], Base10)  %%hex notation
    ).    

digits_to_int(List, Base) ->
    HighestPower = length(List) - 1,
    digits_to_int(List, Base, HighestPower, 0).

digits_to_int([], _, _, Sum) ->
    Sum;
digits_to_int([X|Xs], Base, Power, Sum) when X<Base ->
    Term = round( math:pow(Base, Power) * X ),  %%round() converts float to integer. 
    digits_to_int(Xs, Base, Power-1, Sum+Term);
digits_to_int(_, _, _, _) ->
    throw("illegal_number: Some elements are >= to Base").

%--------------

list_of_digits_test() ->
    Base10 = 10,
    ?assertEqual(
        [1,1],
        list_of_digits(11, Base10)
      ),
    ?assertEqual(
        [1,0,0],
        list_of_digits(100, Base10)
      ),
    ?assertEqual(
        [1],
        list_of_digits(1, Base10)
      ),
    ?assertEqual(
        [],
        list_of_digits(0, Base10)
      ),

    Base2 = 2,
    ?assertEqual(
        [1,0,1,1],
        list_of_digits(2#1011, Base2)
      ),
    ?assertEqual(
        [1,1,1],
        list_of_digits(2#111, Base2)
      ),
    ?assertEqual(
        [1],
        list_of_digits(1, Base2)
      ).

list_of_digits(0, _Base) ->
    [];
list_of_digits(Number, Base) -> %% 193
    HighestPower = get_highest_power(Number, Base),
    list_of_digits(Number, Base, HighestPower, []).

list_of_digits(Number, _, 0, Digits) ->
    lists:reverse([Number|Digits]);
list_of_digits(Number, Base, Power, Digits) ->
    X = round(math:pow(Base, Power) ),
    Digit = Number div X,
    Remainder = Number rem X,
    list_of_digits(Remainder, Base, Power-1, [Digit|Digits]).

%---------------

get_highest_power_test() ->
    Base10 = 10,
    ?assertEqual(
        2,
        get_highest_power(199, Base10)
      ),
    ?assertEqual(
        3,
        get_highest_power(1999, Base10)
      ),
    ?assertEqual(
        3,
        get_highest_power(1000, Base10)
      ),
    ?assertEqual(
        1,
        get_highest_power(19, Base10)
      ),
    ?assertEqual(
        0,
        get_highest_power(5, Base10)
      ).

get_highest_power(Number, Base) ->
    Power = 0,
    KeepGoing = (Number div round(math:pow(Base,Power)) ) > 0,
    get_highest_power(Number, Base, Power, KeepGoing).

get_highest_power(Number, Base, Power, KeepGoing) when KeepGoing =:= true ->
    NewPower = Power+1,
    StillKeepGoing = (Number div round(math:pow(Base, NewPower)) ) > 0,
    get_highest_power(Number, Base, NewPower, StillKeepGoing); 
get_highest_power(_, _, Power, KeepGoing) when KeepGoing =:= false ->
    max(0, Power - 1).

Upvotes: 0

Ivan
Ivan

Reputation: 56

Here is solution that doesn't use list_to_integer or integer_to_list. Algorithm is called long multiplication and is usually used when language does not support multiplication/sum of big (larger than INT.MAX) numbers. Below is basic implementation that can be optimized in various ways, but will work just fine for education purposes.

Keep in mind that Erlang supports long multiplication and long sum out of the box (as opposed to, say, C), so implementing multiplication is useless in real life applications.

sum(A, B) when is_list(A) andalso is_list(B) -> 
  lists:reverse(sum_impl(lists:reverse(A), lists:reverse(B), {[], 0})).
mult(A, B) when is_list(A) andalso is_list(B) -> 
  lists:reverse(mult_impl(lists:reverse(A), lists:reverse(B), {[], []})).

sum_impl([], [], {Res, 0}) -> Res;
sum_impl([], [], {Res, C}) -> sum_impl([C], [0], {Res, 0});
sum_impl(A, [], Acc) -> sum_impl(A, [0], Acc);
sum_impl([], B, Acc) -> sum_impl([0], B, Acc);
sum_impl([HA | TA], [HB | TB], {Res, C}) ->
  sum_impl(TA, TB, {Res ++ [(HA + HB + C) rem 10], (HA + HB + C) div 10}).

mult_impl(_A, [], {Res, _C}) -> Res;
mult_impl(A, [HB | TB], {Res, C}) ->
  mult_impl(A, TB, {sum_impl(Res, C ++ [X * HB || X <- A], {[], 0}), [0 | C]}).

Upvotes: 1

user4651282
user4651282

Reputation:

For example, so:

multi(List, N) when is_number(N) ->
  element(1,
    lists:foldr(
      fun(X, {Sum, Index}) -> {Sum + X * N * pow10(Index), Index + 1} end,
      {0, 0}, List));
multi(L1, L2) when is_list(L2) ->
  List = [fun() -> multi(L1, X) end() || X <- L2],
  element(1,
    lists:foldr(
      fun(X, {Sum, Index}) -> {Sum + X * pow10(Index), Index + 1} end,
      {0, 0}, List)).

pow10(N) when N =:= 0 -> 1;
pow10(N) -> 10 * pow10(N - 1).

If a notice that foldr expressions similar , it is possible to simplify the code:

multi(List, N) when is_number(N) ->
  element(1,
    lists:foldr(
      fun(X, {Sum, Index}) -> {Sum + X * N * pow10(Index), Index + 1} end,
      {0, 0}, List));
multi(L1, L2) when is_list(L2) ->
  multi([fun() -> multi(L1, X) end() || X <- L2], 1).

pow10(N) when N =:= 0 -> 1;
pow10(N) -> 10 * pow10(N - 1).

for getting list, use integer_to_list:

...
multi(L1, L2) when is_list(L2) ->
 create_list(multi([fun() -> multi(L1, X) end() || X <- L2],1)).

create_list(Number)->
  [X-48 || X<-integer_to_list(Number)].
...

Upvotes: 1

Related Questions