我正在尝试使用素数因子分解数字。我想使用if语句测试条件,如果因子是一个因子,则创建一个列表。它不起作用,我想不出任何其他方式它可以工作,建议?
factor( N ) ->
if
N rem factor(N-1) == 0 ->
[N|factor(N-1)];
true -> false;
end.
答案 0 :(得分:1)
此代码执行分解,但我不使用if语句(在Erlang IMHO中不常见):
%% this function is here to hide the detail of parameters needed for the tail recursion
decomp(N) when is_integer(N), (N > 0) ->
lists:reverse(decomp(N,[],2)).
%% generally in recursion the first clause is the stop condition
decomp(N,R,I) when I*I > N -> [N|R];
%% this is what you put in your if statement, is N is divided by I, then I is a factor of N
%% so add I in the list of factors and continue with (N div I) and I (it can be a multiple factor
decomp(N,R,I) when (N rem I) =:= 0 -> decomp(N div I,[I|R],I);
%% this clause is reached if I does not divide N, so simply skip it and go to 3 or I+2
decomp(N,R,2) -> decomp(N,R,3);
decomp(N,R,I) -> decomp(N,R,I+2).
我记录了一个例子的执行跟踪。注意,decomp / 3是尾递归的,因此长返回阶段实际上是单个返回。
1> help_num:decomp(70610).
++ (3) <147> decomp(70610,[],2)
++ (4) <150> decomp(35305,[2],2)
++ (5) <151> decomp(35305,[2],3)
++ (6) <152> decomp(35305,[2],5)
++ (7) <150> decomp(7061,[5,2],5)
++ (8) <152> decomp(7061,[5,2],7)
++ (9) <152> decomp(7061,[5,2],9)
++ (10) <152> decomp(7061,[5,2],11)
++ (11) <152> decomp(7061,[5,2],13)
++ (12) <152> decomp(7061,[5,2],15)
++ (13) <152> decomp(7061,[5,2],17)
++ (14) <152> decomp(7061,[5,2],19)
++ (15) <152> decomp(7061,[5,2],21)
++ (16) <152> decomp(7061,[5,2],23)
++ (17) <150> decomp(307,[23,5,2],23)
-- (17) [307,23,5,2]
-- (16) [307,23,5,2]
-- (15) [307,23,5,2]
-- (14) [307,23,5,2]
-- (13) [307,23,5,2]
-- (12) [307,23,5,2]
-- (11) [307,23,5,2]
-- (10) [307,23,5,2]
-- (9) [307,23,5,2]
-- (8) [307,23,5,2]
-- (7) [307,23,5,2]
-- (6) [307,23,5,2]
-- (5) [307,23,5,2]
-- (4) [307,23,5,2]
-- (3) [307,23,5,2]
++ (3) <147> lists:reverse([307,23,5,2])
[2,5,23,307]
2>
答案 1 :(得分:0)
初看起来,我在代码中看到两件不起作用的东西:
该函数应该返回一个列表。因此,测试“N rem factor(N-1)== 0”将计算列表的剩余部分除以数字,这没有任何意义。您无法在列表中执行除法。
if guard中有一个递归调用,不支持。
除非您更详细地解释代码应该如何运作,否则我认为我不能提供更好的帮助。
答案 2 :(得分:0)
有一个实现示例。您无需关注next_may_be_prime/2
。您可以使用简单的Old + 2
。这只是优化。
-module(factor).
-export([factor/1, make_wheels/0]).
factor(X) when is_integer(X), X > 0 ->
factor(X, 2, first_primes_steps()).
factor(X, X, _) -> [X];
factor(X, Prime, Wheel) when X rem Prime =:= 0 ->
[Prime|factor(X div Prime, Prime, Wheel)];
factor(X, Old, Wheel) when Old*Old < X ->
{MayBePrime, Wheel2} = next_may_be_prime(Old, Wheel),
factor(X, MayBePrime, Wheel2);
factor(X, _, _) -> [X].
%%% Prime candidates generator
next_may_be_prime(X, [Add|T]) ->
{X+Add, case T of [] -> wheel(); _ -> T end}.
first_primes_steps() -> [1,2,2,4,2].
wheel() ->
[4,2,4,6,2,6,4,2,4,6,6,2,6,4,2,6,4,6,8,4,2,4,2,4,14,4,6,2,
10,2,6,6,4,2,4,6,2,10,2,4,2,12,10,2,4,2,4,6,2,6,4,6,6,6,2,6,
4,2,6,4,6,8,4,2,4,6,8,6,10,2,4,6,2,6,6,4,2,4,6,2,6,4,2,6,10,
2,10,2,4,2,4,6,8,4,2,4,12,2,6,4,2,6,4,6,12,2,4,2,4,8,6,4,6,
2,4,6,2,6,10,2,4,6,2,6,4,2,4,2,10,2,10,2,4,6,6,2,6,6,4,6,6,
2,6,4,2,6,4,6,8,4,2,6,4,8,6,4,6,2,4,6,8,6,4,2,10,2,6,4,2,4,
2,10,2,10,2,4,2,4,8,6,4,2,4,6,6,2,6,4,8,4,6,8,4,2,4,2,4,8,6,
4,6,6,6,2,6,6,4,2,4,6,2,6,4,2,4,2,10,2,10,2,6,4,6,2,6,4,2,4,
6,6,8,4,2,6,10,8,4,2,4,2,4,8,10,6,2,4,8,6,6,4,2,4,6,2,6,4,6,
2,10,2,10,2,4,2,4,6,2,6,4,2,4,6,6,2,6,6,6,4,6,8,4,2,4,2,4,8,
6,4,8,4,6,2,6,6,4,2,4,6,8,4,2,4,2,10,2,10,2,4,2,4,6,2,10,2,
4,6,8,6,4,2,6,4,6,8,4,6,2,4,8,6,4,6,2,4,6,2,6,6,4,6,6,2,6,6,
4,2,10,2,10,2,4,2,4,6,2,6,4,2,10,6,2,6,4,2,6,4,6,8,4,2,4,2,
12,6,4,6,2,4,6,2,12,4,2,4,8,6,4,2,4,2,10,2,10,6,2,4,6,2,6,4,
2,4,6,6,2,6,4,2,10,6,8,6,4,2,4,8,6,4,6,2,4,6,2,6,6,6,4,6,2,
6,4,2,4,2,10,12,2,4,2,10,2,6,4,2,4,6,6,2,10,2,6,4,14,4,2,4,
2,4,8,6,4,6,2,4,6,2,6,6,4,2,4,6,2,6,4,2,4,12,2,12].
%%% Auxiliary functions for making prime wheels
make_wheels() ->
%%%%%%%%%%%%%%%%
Primes = [2,3,5,7,11],
Next = 13,
%%%%%%%%%%%%%%%%
Period = lists:foldl(fun(X, A) -> X*A end, 1, Primes),
Max = Period + Next,
F = fun(X, A) -> array:set(X, false, A) end,
G = fun(X, A) -> lists:foldl(F, A, lists:seq(X, Max, X)) end,
Sieve = lists:foldl(G, array:new([{default, true}]), Primes),
{
diffs(Primes ++ [Next]),
diffs([ X || X <- lists:seq(Next, Max), array:get(X, Sieve)])
}.
diffs([H|T]) ->
diffs(H, T).
diffs(_, []) -> [];
diffs(A, [B|T]) -> [B-A|diffs(B, T)].