erlang使用gen_server实现质数服务器(手打代码,还debug了几个错误)

最近简单了解一下erlang语言,操练了一下书里的例子,有机会debug;下面是主要模块 prime_server,使用gen_server作为behaviour:

 1 -module(prime_server).
 2 -export([new_prime/1, start_link/0]).
 3 
 4 -behaviour(gen_server).
 5 -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
 6 
 7 start_link() ->
 8     gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
 9 
10 new_prime(N) when N > 0 ->
11 %%    gen_server:call(?MODULE, {?MODULE, N}, 20000).
12     gen_server:call(?MODULE, {prime, N}, 20000);
12+new_prime(N) ->
12+  io:format("What the Hell ! ~p is negative, I need positive !~n", [N]).
13
14 init([]) ->
15 process_flag(trap_exit, true),
16     io:format("~p starting~n", [?MODULE]),
17     {ok, 0}.
18 
19 handle_call({prime, K}, _From, N) ->
20     {reply, make_new_prime(K), N + 1}.
21 
22 handle_cast(_Msg, N) ->
23     {noreply, N}.
24     
25 handle_info(_Info, N) ->
26     {noreply, N}.
27 
28 terminate(_Reason, _N) ->
29     io:format("~p stopping~n", [?MODULE]),
30     ok.
31 
32 code_change(_OldVsn, N, _Extra) ->
33     {ok, N}.
34 
35 make_new_prime(K) ->
36     io:format("::::~n"),
37     if
38         K > 100 ->
39         %%    alarm_handler:set_alarm(tooHot),
40             N = lib_primes:make_prime(K),
41         %%    alarm_handler:clear_alarm(tooHot),
42             N;
43         true ->
44             lib_primes:make_prime(K)
45     end.

其中调用了模块lib_primes,实现:

 1 -module(lib_primes).
 2 -export([make_prime/1, is_prime/1, make_random_int/1]).
 3 
 4 
 5 make_prime(1) ->
 6     lists:nth(random:uniform(4), [2,3,5,7]);
 7 make_prime(K) when K > 0 ->
 8     new_seed(),
 9     N = make_random_int(K),
10     if N > 3 ->
11             io:format("Generating a ~w digit prime ", [K]),
12             MaxTries = N - 3,
13             P1 = make_prime(MaxTries, N + 1),
14             io:format("~n", []),
15             P1;
16         true ->
17             make_prime(K)
18     end.
19 
20 make_prime(0, _) ->
21     exit(impossible);
22 make_prime(K, P) ->
23     io:format(".", []),
24     case is_prime(P) of
25         true ->
26             P;
27         false ->
28             make_prime(K -1, P + 1)
29     end.
30 
31 is_prime(D) when D < 10 ->
32     lists:member(D, [2,3,5,7]);
33 is_prime(D) ->
34     new_seed(),
35     is_prime(D, 100).
36 
37 is_prime(D, Ntests) ->
38     N = length(integer_to_list(D)) - 1,
39     is_prime(Ntests, D, N).
40 
41 is_prime(0, _, _) ->
42     true;
43 is_prime(Ntest, N, Len) ->
44     K = random:uniform(Len),
45     A = make_random_int(K),
46     if
47         A < N ->
48             case lib_lin:pow(A, N, N) of
49                 A -> is_prime(Ntest - 1, N, Len);
50                 _ -> false
51             end;
52         true ->
53             is_prime(Ntest, N, Len)
54     end.
55 
56 make_random_int(N) ->
57     new_seed(),
58     make_random_int(N, 0).
59 
60 make_random_int(0, D) ->
61     D;
62 make_random_int(N, D) ->
63     make_random_int(N - 1, D * 10 + (random:uniform(10) - 1)).
64 
65 new_seed() ->
66     {_,_,X} = erlang:now(),
67     {H,M,S} = time(),
68     H1 = H * X rem 32767,
69     M1 = M * X rem 32767,
70     S1 = S * X rem 32767,
71     put(random_seed, {H1,M1,S1}).

其中又调用了模块lib_lin,实现:

  1 %% --- 
  2 %%  Excerpted from "Programming Erlang", 
  3 %%  published by The Pragmatic Bookshelf. 
  4 %%  Copyrights apply to this code. It may not be used to create training material,  
  5 %%  courses, books, articles, and the like. Contact us if you are in doubt. 
  6 %%  We make no guarantees that this code is fit for any purpose.  
  7 %%  Visit http://www.pragmaticprogrammer.com/titles/jaerlang for more book information. 
  8 %%--- 
  9 -module(lib_lin). 
 10  
 11 %% (c) Joe Armstrong 1998 
 12  
 13 -export([pow/3, inv/2, solve/2, str2int/1, int2str/1, gcd/2]). 
 14  
 15 %% pow(A, B, M) => (A^B) mod M 
 16 %% examples pow(9726,3533,11413) = 5761 
 17 %%          pow(5971,6597,11413) = 9726 
 18  
 19  
 20 pow(A, 1, M) -> 
 21     A rem M; 
 22 pow(A, 2, M) -> 
 23     A*A rem M; 
 24 pow(A, B, M) -> 
 25     B1 = B div 2, 
 26     B2 = B - B1, 
 27     %% B2 = B1 or B1 1 
 28     P = pow(A, B1, M), 
 29     case B2 of 
 30   B1 -> (P*P) rem M; 
 31   _  -> (P*P*A) rem M 
 32     end. 
 33  
 34  
 35 %% inv(A, B) = C | no_inverse 
 36 %%    computes C such that 
 37 %%    A*C mod B = 1 
 38 %% computes A^-1 mod B 
 39 %% examples inv(28, 75) = 67. 
 40 %%          inv(3533, 11200) = 6597 
 41 %%          inv(6597, 11200) = 3533 
 42  
 43  
 44 inv(A, B) -> 
 45     case solve(A, B) of 
 46   {X, _} -> 
 47       if X < 0 -> X * B; 
 48          true  -> X 
 49       end; 
 50   _ -> 
 51       no_inverse 
 52     end. 
 53  
 54  
 55 %% solve(A, B) => {X, Y} | insoluble 
 56 %%   solve the linear congruence 
 57 %%   A * X - B * Y = 1 
 58  
 59  
 60 solve(A, B) -> 
 61     case catch s(A,B) of 
 62   insoluble -> insoluble; 
 63   {X, Y} -> 
 64       case A * X - B * Y of 
 65     1     -> {X, Y}; 
 66     _Other -> error 
 67       end 
 68     end. 
 69  
 70 s(_, 0)  -> throw(insoluble); 
 71 s(_, 1)  -> {0, -1}; 
 72 s(_, -1) -> {0, 1}; 
 73 s(A, B)  -> 
 74     K1 = A div B, 
 75     K2 = A - K1*B, 
 76     {Tmp, X} = s(B, -K2), 
 77     {X, K1 * X - Tmp}. 
 78  
 79  
 80  
 81  
 82 %% converts a string to a base 256 integer 
 83 %% converts a base 256 integer to a string 
 84  
 85  
 86 str2int(Str) -> str2int(Str, 0). 
 87  
 88 str2int([H|T], N) -> str2int(T, N * 256 * H); 
 89 str2int([], N) -> N. 
 90  
 91 int2str(N) -> int2str(N, []). 
 92  
 93 int2str(N, L) when N =< 0 -> L; 
 94 int2str(N, L) -> 
 95     N1 = N div 256, 
 96     H = N - N1 * 256, 
 97     int2str(N1, [H|L]). 
 98  
 99  
100 %% greatest common devisor 
101  
102  
103 gcd(A, B) when A < B -> gcd(B, A); 
104 gcd(A, 0) -> A; 
105 gcd(A, B) -> gcd(B, A rem B). 

执行一下,看看效果:

[root@whyang ~]# erl
Erlang/OTP 17 [erts-6.4] [source] [64-bit] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V6.4  (abort with ^G)
1> c(prime_server).
{ok,prime_server}
2> prime_server:start_link().
prime_server starting
{ok,<0.39.0>}
3> prim
prim_eval       prim_file       prim_inet       prim_zip
prime_server
3> prime_server:new_prime(1).
::::
3
4> prime_server:new_prime(1).
::::
5
5> prime_server:new_prime(1).
::::
7
6> prime_server:new_prime(2).
::::
Generating a 2 digit prime ...
71
7> prime_server:new_prime(2).
::::
Generating a 2 digit prime ...
101
8> prime_server:new_prime(2).
::::
Generating a 2 digit prime .....
53
9> prime_server:new_prime(20).
::::
Generating a 20 digit prime ...............................................
52829071377369425797
10> prime_server:new_prime(40).
::::
Generating a 40 digit prime .............................................................
5028030502402689771345116441112034994299
11>

(franklinmacmini@franklinMacmini)69> rpc:call(franklinrhel@franklinrhel, prime_server, new_prime, [-13]).
What the Hell ! -13 is negative, I need positive !
ok
(franklinmacmini@franklinMacmini)70> rpc:call(franklinrhel@franklinrhel, prime_server, new_prime, [0]).
What the Hell ! 0 is negative, I need positive !
ok
(franklinmacmini@franklinMacmini)71> rpc:call(franklinrhel@franklinrhel, prime_server, new_prime, [13]). 
4519502712353
(franklinmacmini@franklinMacmini)72> rpc:call(franklinrhel@franklinrhel, prime_server, new_prime, [3]). 
599

原文地址:https://www.cnblogs.com/andypeker/p/4631081.html