2012-01-19 14 views
7

2点 - 最初の例はFortranですが、どの言語にも当てはまるはずです。第2に、組み込みの乱数ジェネレータは本当にランダムではなく、他のジェネレータも存在しますが、私たちが行っていることにそれらを使用することには興味がありません。乱数シードの可能なソース

ランダムシードに関する多くの議論では、プログラムが実行時にそれをシードしないと、コンパイル時にシードが生成されることを認識しています。したがって、プログラムが実行されるたびに同じ番号のシーケンスが生成されますが、これは乱数には適しません。これを克服する1つの方法は、乱数ジェネレータにシステムクロックを設定することです。

しかし、マルチコアマシン上でMPIと並行して実行すると、システムクロックのアプローチによって同じ種類の問題が発生しました。シーケンスは実行ごとに変わりましたが、すべてのプロセッサは同じシステムクロックを持ち、同じランダムシードと同じシーケンスを持っていました。

したがって、次のコード例で考えてみます。だから、

OLD Rank, dev =   0 0.330676306089146  
OLD Rank, dev =   1 0.330676306089146  
NEW Rank, dev =   0 0.531503215980609  
NEW Rank, dev =   1 0.747413828750221  

を、私たちは/dev/urandomから種子を読み取ることによって、クロックの問題を克服:与え、2つのコアで私のワークステーション上で実行

PROGRAM clock_test 
    IMPLICIT NONE 
    INCLUDE "mpif.h" 
    INTEGER :: ierr, rank, clock, i, n, method 
    INTEGER, DIMENSION(:), ALLOCATABLE :: seed 
    REAL(KIND=8) :: random 
    INTEGER, PARAMETER :: OLD_METHOD = 0, & 
         NEW_METHOD = 1 

    CALL MPI_INIT(ierr) 

    CALL MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr) 

    CALL RANDOM_SEED(SIZE=n) 
    ALLOCATE(seed(n)) 

    DO method = 0, 1 
     SELECT CASE (method) 
     CASE (OLD_METHOD) 
     CALL SYSTEM_CLOCK(COUNT=clock) 
     seed = clock + 37 * (/ (i - 1, i = 1, n) /) 
     CALL RANDOM_SEED(put=seed) 
     CALL RANDOM_NUMBER(random) 

     WRITE(*,*) "OLD Rank, dev = ", rank, random 
     CASE (NEW_METHOD) 
     OPEN(89,FILE='/dev/urandom',ACCESS='stream',FORM='UNFORMATTED') 
     READ(89) seed 
     CLOSE(89) 
     CALL RANDOM_SEED(put=seed) 
     CALL RANDOM_NUMBER(random) 

     WRITE(*,*) "NEW Rank, dev = ", rank, random 
     END SELECT 
     CALL MPI_BARRIER(MPI_COMM_WORLD, ierr) 
    END DO 

    CALL MPI_FINALIZE(ierr) 
END PROGRAM clock_test 

を代わりに。このようにして、各コアは独自の乱数を取得します。

マルチコアのMPIシステムでも動作し、実行ごとに各コアで一意になる他のシードアプローチはありますか?

答えて

10

Katzgrabber(テクニカルコンピューティングのためのPRNGの使い方の優れた明快な議論)で、Random Numbers In Scientific Computing: An Introductionを見ると、並列に、時間とPIDのハッシュ関数を使ってシードを生成することを提案します。そのセクション7.1から:もちろん

long seedgen(void) { 
    long s, seed, pid; 

    pid = getpid(); 
    s = time (&seconds); /* get CPU seconds since 01/01/1970 */ 

    seed = abs(((s*181)*((pid-83)*359))%104729); 
    return seed; 
} 

、Fortranでこれは

function seedgen(pid) 
    use iso_fortran_env 
    implicit none 
    integer(kind=int64) :: seedgen 
    integer, intent(IN) :: pid 
    integer :: s 

    call system_clock(s) 
    seedgen = abs(mod((s*181)*((pid-83)*359), 104729)) 
end function seedgen 

ようなものになるだろうことは、むしろseedgenの中からそれを呼び出すよりも、時間に渡すことができることも、時には便利ですテストするときに、再現可能な(==テスト可能な)シーケンスを生成する固定値を与えることができます。

0

システム時間は、通常、整数型で返されます(または少なくとも簡単に変換されます)。単純にプロセスのランクを値に追加し、それを使用して乱数ジェネレータをシードします。

+0

http://stackoverflow.com/questions/1554958/how-different-do-random-seeds-need-to-beに関するディスカッションとその回答に引用された記事に基づいて、ランクを時間に追加するだけですすべてのシードが線形であるため、擬似乱数を生成します。しかし、擬似乱数のみが問題ない場合は、時間+順位のアプローチは非常に簡単でプラットフォームに依存しません。 – tpg2114

関連する問題