Reputation: 17
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
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
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
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