2017-04-26 11 views
1

私はgfortran大気輸送モデルコードでMPI_REDUCE呼び出しで数日間戦っていましたが、良い入力パラメータを持っていましたが、マスターのrecvbufで非常に不当な結果を返しました。私は次のように、簡単な例では、問題を再現することができました:MPI_REDUCEが1000x1000x6のREAL配列に対して間違った答えを返す

PROGRAM TEST 

    USE mpi 

    IMPLICIT NONE 

    INTEGER my_rank, size, ierror 
    INTEGER, PARAMETER :: nx=1000, ny=1000, nz=6 
    INTEGER :: buffsize 

    REAL, DIMENSION(nx, ny, nz) :: u, v 

    call MPI_INIT(ierror) 
    call MPI_COMM_SIZE(MPI_COMM_WORLD, size, ierror) 
    call MPI_COMM_RANK(MPI_COMM_WORLD, my_rank, ierror) 

    PRINT *, 'my_rank, size: ', my_rank, size 

    buffsize = nx*ny*nz 

    u = my_rank + 1 

    PRINT *, 'PE: ', my_rank, ', Before reduce, SHAPE(u): ', SHAPE(u) 
    PRINT *, 'PE: ', my_rank, ', Before reduce, SUM(u): ', SUM(u) 

    CALL MPI_REDUCE(u, v, buffsize, MPI_REAL, & 
&     MPI_SUM, 0, MPI_COMM_WORLD, ierror) 

    CALL MPI_BARRIER(MPI_COMM_WORLD, ierror) 

    PRINT *, 'PE: ', my_rank, ', after reduce, ierror: ', ierror 
    PRINT *, 'PE: ', my_rank, ', after reduce, SUM(u): ', SUM(u) 
    PRINT *, 'PE: ', my_rank, ', after reduce, SUM(v): ', SUM(v) 

    CALL MPI_FINALIZE(ierror) 

END PROGRAM test 

それが返されます。

mpirun -np 2 ./test3 
my_rank, size:   0   2 
my_rank, size:   1   2 
PE:   1 , Before reduce, SHAPE(u):   1000  1000   6 
PE:   0 , Before reduce, SHAPE(u):   1000  1000   6 
PE:   0 , Before reduce, SUM(u): 6000000.00  
PE:   1 , Before reduce, SUM(u): 12000000.0  
PE:   0 , after reduce, ierror:   0 
PE:   1 , after reduce, ierror:   0 
PE:   1 , after reduce, SUM(u): 12000000.0  
PE:   0 , after reduce, SUM(u): 6000000.00  
PE:   1 , after reduce, SUM(v): 0.00000000  
PE:   0 , after reduce, SUM(v): 18407592.0  

PE0が最後にSUMとして18000000.0(V)を示すことが「必要があります」ライン。

コードのnzパラメータを6から5に設定すると、正しい結果が得られます。本当に混乱するのは、a)gfortran 5.3とopenmpiを使用したAWS EC2インスタンス、b)mpichを使用したラップトップのgfortran 5.4、c)openmpiを使用したワークステーションのgfortran 4.4など、同じ値を返すということです。

配列の型をDOUBLE PRECISIONに変更した場合(MPI_REDUCE呼び出しで指定された井戸のように)、はるかに大きな配列でもうまく動作します。 REALではなくREAL4を使用すると、同じ結果が得られます。

私はこれが単純でなければならないことを知っています。私はここで本当のばかだと思っていますが、私はこれを理解していません。私は私のバッファサイズが2^31-1未満の整数値である必要があるといういくつかの提案を読んだが、確かにここに当てはまる。

答えて

3

これはMPI、それだけで合計精度の問題とは何の関係もありません:

PROGRAM TEST 
    IMPLICIT NONE 
    INTEGER, PARAMETER :: nx=1000, ny=1000, nz=6 
    REAL, DIMENSION(nx, ny, nz) :: u 
    u = 3 
    PRINT *, SUM(u) 
END PROGRAM test 

は同じ結果を返します。少数に大きな数を追加すると、丸めの問題が発生する可能性があります。多数の小数の合計で、この影響が重大な誤差に累積する可能性があります。この効果を防​​ぐための加算アルゴリズムがあります。たとえば、Kahan summationのように、明らかにFortranのSUMはこのように実装されていません。

+4

Fortranは実際に 'sum'がどのように動作するかを指定せず、単に結果に「プロセッサーに依存する近似値に等しい値があります」と指定していません。異なるコンパイラはこれを[この他の質問](https://stackoverflow.com/q/25316371)に見られるように、実装品質の問題として扱います。 – francescalus

関連する問題