续接前文,通过erlang的并发方式计算并获取质数序列
%% @author ANDY
%% @doc @todo Add description to eg003.
-module(eg003).
-compile({no_auto_import,[length/1]}).
%%
====================================================================
%% API functions
%%
====================================================================
-export([sum/1,
ranges/3,
is_prime_number/1,
pns_2toN/1,
pns_NtoM/2,
rangeN/2,
c_pns_NtoM/4,
get_pn_lst/2,
get_pn_NtoM/2,
all_the_proper_divisors/1,
sum_proper_divisors/1,
list_perfect_numbers/1,
list_amicable_numbers/1,
list_amicable_numbers/2,
list_prime_numbers/1,
list_nums/1,
list_of_prime_numbers_2toN/1,
length/1,
show/1]).
%%
====================================================================
%% Internal functions
%%
====================================================================
%辅助函数,对列表求和
sum(Alist) -> sum(Alist, 0).
sum([], N) -> N;
sum([H|T], N) -> sum(T, H + N).
%range(N, N) -> [N];
%range(Min, Max) -> [Min | range(Min + 1, Max)].
%range({A, B}) -> range(A, B).
%辅助函数,生成整数序列
range(A, B) -> range(B, A, []).
range(N, N, L) -> [N|L];
range(Max, Min, L) -> range(Max - 1, Min, [Max | L]).
%辅助函数,生成间距S的整数序列
ranges(A, B, S) -> ranges(B, A, [], S).
ranges(Max, Min, L, _) when Max < Min -> L;
ranges(Max, Min, L, S) when Max < Min + S -> [Min|L];
ranges(Max, Min, L, S) -> ranges(Max, Min + S, [Min | L],
S).
%获得N的全部约数
all_the_proper_divisors(N) -> % N > 6!
Range = range(1, N div 2),
[X || X
%获得N的全部约数的和
sum_proper_divisors(N) ->
sum(all_the_proper_divisors(N)).
%获得2至N的质数序列,记作方式1
list_prime_numbers(N) -> % N > 1
[X || X
=:= 1].
%获得6至N的完全数序列
list_perfect_numbers(N) -> % N > 6
[X || X
sum_proper_divisors(X)].
%获得6至N的亲和数序列
list_amicable_numbers(N) -> % N > 6
[{X, sum_proper_divisors(X)} || X
N),
X
< sum_proper_divisors(X),
X
=:= sum_proper_divisors(sum_proper_divisors(X))].
%获得Min至Max的亲和数序列
list_amicable_numbers(Min, Max) -> % N > 6
[{X, sum_proper_divisors(X)} || X
range(Min, Max),
X
< sum_proper_divisors(X),
X
=:= sum_proper_divisors(sum_proper_divisors(X))].
%辅助函数,显示数据
show(Value) -> io:format("It is ~p~n", [Value]).
%测试函数
list_nums(N) ->
show([{X, sum_proper_divisors(X)} || X
range(6, N)]).
%实现获取2至N的质数序列,记作方式2
list_of_prime_numbers_2toN(N) -> list_of_prime_numbers(range(2,
N)).
list_of_prime_numbers([H]) -> [H];
list_of_prime_numbers([H|T]) -> [H |
list_of_prime_numbers(update_list(H, T))].
update_list(H, T) -> reverse(update_list(H, T, [])).
update_list(_, [], L) -> L;
update_list(H, [He|T], L) ->
case (He rem H =:= 0) of
true -> update_list(H, T,
L);
false -> update_list(H, T,
[He|L])
end.
%辅助函数,获得序列的逆序
reverse(L) -> reverse(L, []).
reverse([], L) -> L;
reverse([H|T], L) -> reverse(T, [H|L]).
%辅助函数,获得序列的长度
length(L) -> length(L, 0).
length([], R) -> R;
length([_|T], R) -> length(T, R + 1).
%辅助函数,判断整数N是否为偶数
even(N) -> if N rem 2 == 0 -> true;
N rem 2 /= 0 -> false
end.
%子函数,判断整数N是否为质数,记作方式3
is_prime_number(N) ->
case even(N) of
true -> if N == 2 ->
true;
N /= 2 -> false
end;
false -> T =
trunc(math:sqrt(N)),
if N == 3 -> true;
N
/= 3 -> is_pn0(3, T, N)
end
end.
is_pn0(V, T, N) when T < V + 2 -> if N rem V == 0 ->
false;
N rem V /= 0 -> true
end;
is_pn0(V, T, N) -> if N rem V == 0 -> false;
N rem V /= 0 -> is_pn0(V + 2, T, N)
end.
%获得2至N的质数序列
pns_2toN(N) -> % N > 2
L = [E || E
is_prime_number(E) == true],
[2|reverse(L)].
%获得N至M的质数序列
pns_NtoM(N, M) ->
case even(N) of
true -> if N == 2
->
[E || E
[2];
N /= 2 ->
[E || E
true]
end;
false -> [E || E
ranges(N, M, 2), is_prime_number(E) == true]
end.
%子函数, 获得N至M的质数序列
c_pns_NtoM(Pid, N, M, V) ->
case even(N) of
true -> if N == 2
->
L = [E || E
++ [2],
Pid ! {lst, L, V};
N /= 2 ->
L = [E || E
true],
Pid ! {lst, L, V}
end;
false ->
L = [E || E
Pid ! {lst,
L, V}
end.
%子函数, 获得完整质数序列
get_pn_lst(L, N) ->
receive
{lst, M, V} when V == N + 1
->
{ok, File} =
file:open("res.txt", write),
io:format(File,
"~p~n~nlength: ~p~n", [[M|L], sum([length(E) || E
file:close(File);
%io:format("~p~n",
[[M|L]]);
{lst, M, _} ->
get_pn_lst([M|L], N + 1)
end.
%子函数,询问并发过程是否结束
%asking_for(Pid, V, From) ->
% Pid ! {'is_ok?', V, self()},
% receive
% {ok, L} -> From ! {ok,
L};
% _ -> asking_for(Pid, V,
From)
% end.
%辅助函数,对区间[N, M]等距分段
rangeN(N, M) ->
T0 = M - N + 1,
T1 = trunc(math:sqrt(T0)),
T2 = T0 div T1,
[{N + (I - 1) * T2, N + I * T2 - 1} || I
range(1, T1 - 1)] ++ [{N + (T1 - 1) * T2, M}].
%获得N至M的质数序列,使用方式3,较方式2及1代价更小2
get_pn_NtoM(N, M) ->
L = rangeN(N, M),
V = length(L),
Pid = spawn(?MODULE, get_pn_lst, [[], 0]),
[spawn(?MODULE, c_pns_NtoM, [Pid, E1, E2, V]) ||
{E1, E2}
%L1 = [rangeN(E1, E2) || {E1, E2}
%[[reverse(pns_NtoM(E1, E2)) || {E1, E2}
NL] || NL
%[reverse(pns_NtoM(E1, E2)) || {E1, E2}
L]
%eg003:get_pn_NtoM(2, 10000000)
获得2至1千万内的质数序列
尽管1千万中的质数获得成功了,但是计算一亿内的质数时没有能够成功获得成功的输出!较好的并发方式仍在未来;为了获得1亿内的质数,采取了如下的方案:
// ANDY
// Using FSharp
// 初学F#,使用基础知识获取质数序列
//(*
// 开胃菜---"小玩具", 获得列表长度的3种实现
let rec len lst =
match lst
with
| [] ->
0
| h :: t
-> 1 + len t
let len2 lst =
let rec len0
lst r =
match lst with
| [] -> r
| h :: t -> len0 t (r + 1)
len0 lst
0
let len3 (lst:'T list) = lst.Length
//*)
// 主菜: 方式一
//部分一:判断n是否是质数
let isPrimeNumber n =
let
quickJuage x =
let t = x |> float |> sqrt |> int
let lst = [3..2..t]
let rec inJuage (alst: int list) =
match alst with
|[] -> true
|h::t when x % h = 0 -> false
|h::t -> inJuage t
inJuage lst
match n
with
|_ when n =
2 -> true
|_ when n %
2 = 0 -> false
|_ -> quickJuage n
//辅助功能,获得分段序列
let ranges n m =
let t0 = m -
n + 1
let t1 = t0
|> float |> sqrt |> int
let t2 = t0
/ t1
[for i in
[1..t1-1] -> (n + (i - 1) * t2, n + i * t2 - 1)] @ [(n + (t1 -
1) * t2, m)]
//部分二:获得区间内的质数序列
let arrOfPrimeNumsNtoM n m =
let arr =
match n with
|_ when n = 2 -> Array.append [|2|] [|3..2..m|]
|_ when n % 2 = 0 -> [|n + 1..2..m|]
|_ -> [|n..2..m|]
Array.filter
isPrimeNumber arr
//强化,获得序列包含元素数目
let moreArrOfPrimeNumsNtoM n m =
let res =
arrOfPrimeNumsNtoM n m
(res,
res.Length)
//计算n至m中的质数序列
let thePrimeNumsNtoM n m =
let lst =
ranges n m
let rec go
lst arr =
match lst with
|[] -> arr
|(a, b) :: t -> go t (Array.append arr (arrOfPrimeNumsNtoM a
b))
go lst
[||]
//为了获得一亿内的质数,根据方式一的思想,设计的特别版本
let outputPrimeNumsNtoM n m =
let arr =
match n with
|_ when n = 2 -> Array.append [|2|] [|3..2..m|]