Erlang-蒙特卡洛方法求Pi

这里面有两种方法,核数为2的幂见代码1,核数不为2的幂见代码2.
代码1:

-module(exe5_2).
-export([start/2]).
%Points 是投掷点的个数 Cores是核数,为2的幂
start(Points,Cores)
    ->spawn(fun()->parent_proces(Points,Cores) end),
    io:format("").

parent_proces(Points,Cores) ->
        PointsPerProcess = Points div Cores,
        creat_child_proces(Points,PointsPerProcess,Cores,Cores,[]).

%创建子进程
creat_child_proces(Points,PointsPerProcess,Cores,N,L) 
      when N =:=1 -> 
      Pid = spawn(fun()->process_points(Points,Points-PointsPerProcess*(Cores-1)) end),  
      Father = self(),
      PidR = spawn(fun()->loop_control(Father,0,Cores,2) end),
      sendInfo(L++[Pid]++[PidR],1,Cores,2,Cores);

creat_child_proces(Points,PointsPerProcess,Cores,N,L)
      ->Pid=spawn(fun()->process_points(Points,PointsPerProcess) end),
        creat_child_proces(Points,PointsPerProcess,Cores,N-1,L++[Pid]).

%计算命中的点 
process_points(Points,PointsPerProcess) ->
    apply(random, seed, tuple_to_list(now())),
    Count = test_points(PointsPerProcess, 0),
    io:format("~p 's result is ~p~n",[self(),Count]),
    loop_send_get(Points,Count).

test_points(0, Count) -> Count;

test_points(PointsPerProcess, Count) ->
    X = (random:uniform() * 2) - 1,
    Y = (random:uniform() * 2) - 1,
    I = X*X + Y*Y,
    if
        I < 1 ->
            test_points(PointsPerProcess - 1, Count + 1);
        true ->
            test_points(PointsPerProcess - 1, Count)
    end.


%子进程部分和的发送和接收,由主进程sendInfo方法控制
loop_send_get(Points,Sum) ->
        receive 
                {From,Sum1,Father,PidR} ->
                        io:format("~p from ~p to ~p result is ~p ~n",[Sum1,From,self(),Sum1+Sum]),
                        PidR!{"ok"},
                        loop_send_get(Points,Sum+Sum1);
                {Pid,Father,PidR} ->
                        Pid!{self(),Sum,Father,PidR};
                {"getRes"} ->Res=(Sum/Points)*4,
                            io:format("Pi:~p~n",[Res])
        end.
%控制每一轮迭代求和的次数,N为一轮迭代中求和的次数,初始值为0,Divisor为控制变量,初始值为2
loop_control(Father,N,Cores,Divisor) ->%io:format("N:~p Divisor:~p~n",[N,Divisor]),
        if
            Cores =:= N*Divisor ->
                                Father!{self(),"over"},
                                loop_control(Father,0,Cores,Divisor*2);
            true ->
                    receive
                        {"ok"} ->   loop_control(Father,N+1,Cores,Divisor)
                    end

        end.

sendInfo(PidList,N,Cores,Divisor,Dsum) ->%io:format("Pidlist:~p ~nN:~p Cores:~p Divisor:~p Dsum:~p ~n",[PidList,N,Cores,Divisor,Dsum]),
                                        Nt = erlang:trunc(N),
            if
                Divisor =:= 2*Dsum -> Pid_1=lists:nth(1,PidList),
                                      Sum=Pid_1!{"getRes"};


                Nt > Cores ->
                        receive
                            {From,"over"} ->sendInfo(PidList,1,Cores-Divisor/2,Divisor*2,Dsum)
                        end;
                Nt rem Divisor =:= 1 ->
                        sendInfo(PidList,N+Divisor/2,Cores,Divisor,Dsum);
                Nt rem Divisor =/= 1 ->
                        Pid_send = lists:nth(Nt,PidList),
                        Pid_get = lists:nth(erlang:trunc(Nt-Divisor/2),PidList),%io:format("send:~p get:~p~n",[Pid_send,Pid_get]),
                        Pid_send!{Pid_get,self(),lists:nth(erlang:trunc(Dsum+1),PidList)},
                        sendInfo(PidList,N+Divisor/2,Cores,Divisor,Dsum)         
            end.

代码2:

-module(exe5_4).
-export([main/2]).

%Points投掷点的总数 Core为核数,任意值
main(Points,CoreNum) ->
                 SumDie=temp(CoreNum,1),
                 PointsPerProcess = Points div CoreNum,
                 createP(1,CoreNum,SumDie,Points,PointsPerProcess),
                 io:format("").

temp(Num,SNum) when Num =< SNum -> SNum;
temp(Num,SNum) -> temp(Num,SNum*2).


createP(N,CoreNum,SumDie,Points,PointsPerProcess) when N =:= CoreNum -> 
               register(integer_to_atom(N),spawn(fun()->process_points(Points,N,2,CoreNum,SumDie,Points,Points-PointsPerProcess*(CoreNum-1)) end));
createP(N,CoreNum,SumDie,Points,PointsPerProcess) -> 
               register(integer_to_atom(N),spawn(fun()->process_points(Points,N,2,CoreNum,SumDie,Points,PointsPerProcess) end)),
               createP(N+1,CoreNum,SumDie,Points,PointsPerProcess).


integer_to_atom(Int) -> T=integer_to_binary(Int),
                        binary_to_atom(T,utf8).

%计算命中的点 
process_points(Points,N,Die,CoreNum,SumDie,Points,PointsPerProcess) ->
  apply(random, seed, tuple_to_list(now())),
  Count = test_points(PointsPerProcess, 0),
  io:format("~p 's result is ~p~n",[self(),Count]),
  loop(Points,N,Die,SumDie,CoreNum,Count).

test_points(0, Count) -> Count;

test_points(PointsPerProcess, Count) ->
  X = (random:uniform() * 2) - 1,
  Y = (random:uniform() * 2) - 1,
  I = X*X + Y*Y,
  if
    I < 1 ->
      test_points(PointsPerProcess - 1, Count + 1);
    true ->
      test_points(PointsPerProcess - 1, Count)
  end.


%每个core 收发信息
loop(Points,Number,Die,SumDie,CoreNum,Count) ->
    if
        Die =:= SumDie*2 -> Res = (Count/Points)*4,
                        io:format("Pi=~p~n",[Res]);

      true -> [H|L]=judge(CoreNum,Number,Die),
            if
                H =:= 1 -> [H2|_]=L,
                        {send,To,DieThat}=H2,
                       (integer_to_atom(To))!{Number,DieThat,Count};
                true -> [H2|_]=L,
                    {get,From,DieThat}=H2,
                    receive
                        {From,DieThat,Count1} -> io:format("~p ~p get info from ~p,the result is ~p~n",[Count1,Number,From,Count+Count1]),
                                    loop(Points,Number,Die*2,SumDie,CoreNum,Count1+Count)
                    end
            end
     end.

%判断每核的收发
judge(SumCore,Number,Die) -> R=lslast(SumCore,Number,Die),
   if
      R =:= 1 ->
         if
            Number rem Die =:= 1 -> {DieThat,To}=find(Number,Die),
                                    [1,{send,To,DieThat}];
            true -> [1,{send,Number-erlang:trunc(Die/2),Die}]
         end;
      true -> 
         if
            Number rem Die =:= 1 -> [0,{get,Number+erlang:trunc(Die/2),Die}];
            true -> [1,{send,Number-erlang:trunc(Die/2),Die}]
         end
   end.

%判断最后一核信息发送给哪里
find(Number,Die) -> Current_order=ceil(Number*2/Die),
   if
      Current_order rem 2 =:= 0 -> {Die,Number-erlang:trunc(Die/2)};
      true -> find(Number,Die*2)
   end.

%计算live的核在本轮迭代中的序号,若为最后一个标记为1.
lslast(SumCores,Number,Die) -> Current_order=ceil(Number*2/Die), 
                               Sum_order=ceil(SumCores*2/Die),
                               io:format("~p ~p ~p ~p ~p~n",[SumCores,Number,Die,Current_order,Sum_order]),
      if
         Current_order =:= Sum_order -> 1;
         true -> 0
      end.

%对小数取上界,比如ceil(15.1)=16
ceil(N) -> T=trunc(N),
           Temp = N-T,
   case Temp =:= 0.000 of
      true -> T;
      false -> T+1
   end.

你可能感兴趣的:(并行计算)