使用list -erlang

时间:2016-05-22 14:05:05

标签: erlang

如何在列表中表示多个两个数字,例如123 * 12 = 1476 我想在这个例子中使用list来执行此操作它应该是这样的 mul([1,2,3],[1,2])结果将为[1,4,7,6],而不会使用list_to_integer函数将列表转换为数字。到目前为止我做到了这一点,但如果其中一个列表的长度等于一个

,它就会正常工作
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.

3 个答案:

答案 0 :(得分:1)

例如,所以:

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).

如果有一个foldr表达式相似的通知,则可以简化代码:

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).

获取列表,请使用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)].
...

答案 1 :(得分:1)

以下是不使用list_to_integerinteger_to_list的解决方案。算法称为long multiplication,通常在语言不支持big(大于INT.MAX)数的乘法/和时使用。以下是可以通过各种方式进行优化的基本实现,但在教育方面可以正常使用。

请记住 Erlang 支持长时间的乘法和开箱即用的长总和(而不是 C ),因此在现实生活中实现乘法是无用的应用。

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]}).

答案 2 :(得分:0)

这是一个允许您指定基数(2-10)的版本:

在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).