2016-05-22 152 views
2

我如何將多個在例如123 * 12 = 1476 列表代表兩個數字要在這個例子中使用列表它應該是這樣的 mul([1,2,3],[1,2])結果將是[1,4,7,6]做此操作無需轉換列表通過使用list_to_integer函數進行編號。我這樣做,但迄今爲止它只是工作,如果列表中的一個的長度等於一個乘兩個列表使用列表-erlang

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. 
+1

你能告訴我們你到目前爲止已經試過了,你得到了什麼結果? –

+0

@SteveVinoski我已發佈我所做的... – koko

+0

請注意'[X * Y || X < - [H],Y <-B]'相當於[H * Y || Y <-B]'因爲'H'是列表中的一個數字 - 不是一個列表本身。 – 7stud

回答

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)]. 
... 
+0

非常感謝你@Atomic它的工作很好,只是如果我想要在列表中顯示結果,例如'multi([43],[1,7]),結果變成'[7,3, 1]'731的instate。 – koko

+0

@koko,你說的對,我的注意力不集中。你可以用integer_to_list分割? –

+0

非常感謝你@Atomic我已經解決了這個部分(轉換結果到列表),但你的解決方案是非常有效的,那麼我的。 – koko

2

這裏是不使用list_to_integerinteger_to_list的解決方案。算法被稱爲long multiplication,通常在語言不支持乘法/和大(大於INT.MAX)數字時使用。以下是可以通過各種方式進行優化的基本實現,但對於教育目的來說工作得很好。

記住二郎支持長乘和長和開箱即用的(而不是,比方說,Ç),因此實現乘法是在現實生活中的應用也沒用。

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