编译器:gfortran-4.8.5
MPI库:OpenMPI-1.7.2(预安装的OpenSuSE 13.2)
该程序:
use mpi
implicit none
real*16 :: x
integer :: ierr, irank, type16
call MPI_Init(ierr)
call MPI_Comm_Rank(MPI_Comm_World, irank, ierr)
if (irank+1==1) x = 2.1
if (irank+1==8) x = 2.8
if (irank+1==7) x = 5.2
if (irank+1==4) x = 6.7
if (irank+1==6) x = 6.5
if (irank+1==3) x = 5.7
if (irank+1==2) x = 4.0
if (irank+1==5) x = 6.8
print '(a,i0,a,f3.1)', "rank+1: ",irank+1," x: ",x
call MPI_AllReduce(MPI_IN_PLACE, x, 1, MPI_REAL16, MPI_MAX, MPI_Comm_World, ierr)
if (irank==0) print '(i0,a,f3.1)', irank+1," max x: ", x
call MPI_Finalize(ierr)
end
我也尝试过
real(16)
,real(kind(1.q0))
。对于此编译器,real(real128)
实际上与real*10
等效。结果是:
> mpif90 reduce16.f90
> mpirun -n 8 ./a.out
rank+1: 1 x: 2.1
rank+1: 2 x: 4.0
rank+1: 3 x: 5.7
rank+1: 4 x: 6.7
rank+1: 5 x: 6.8
rank+1: 6 x: 6.5
rank+1: 7 x: 5.2
rank+1: 8 x: 2.8
1 max x: 2.8
程序会找到
real*10
的真实最大值,并保留MPI_REAL16
。如果MPI_REAL16
对应于real*16
或real(real128)
(如果它们不同),则MPI规范(3.1,第628和674页)不是很清楚。另外,假设
MPI_REAL16
实际上是real(real128)
,并且尝试在程序中使用它会导致另一个问题:Error: There is no specific subroutine for the generic 'mpi_recv' at (1)
Error: There is no specific subroutine for the generic 'mpi_send' at (1)
real*16
不会发生这种情况。(不考虑一个人应该能够通过任何位模式,因此此检查是多余的)
使用16字节实数的正确方法是什么? OpenMPI库是否错误?
最佳答案
尽管这应该在每个MPI实现中都能正常工作,但是一个直接的解决方法是为用Fortran编写的这种类型实现用户定义的归约,因此在C中实现它没有任何问题(这就是MPICH和OpenMPI尝试的方式做所有事情,因此当C无法重现Fortran的行为时会出现问题。
下面是实现此目的的尝试。这是Fortran中用户定义的减少量。我相信经验丰富的现代Fortran程序员可以做得更好。
subroutine sum_real16(iv,iov,n)
implicit none
integer, intent(in) :: n
real*16, intent(in) :: iv(:)
real*16, intent(inout) :: iov(:)
integer :: i
do i = 1,n
iov(i) = iov(i) + iv(i)
enddo
end subroutine sum_real16
subroutine reduce_sum_real16(iv, iov, n, dt)
use, intrinsic :: iso_c_binding, only : c_ptr
use mpi_f08
implicit none
type(c_ptr), value :: iv, iov
integer :: n
type(MPI_Datatype) :: dt
if ( dt .eq. MPI_REAL16 ) then
call sum_real16(iv,iov,n)
endif
end subroutine reduce_sum_real16
program test_reduce_sum_real16
use, intrinsic :: iso_c_binding
use mpi_f08
implicit none
integer, parameter :: n = 10
real*16 :: output(n)
real*16 :: input(n)
real*16 :: error
integer :: me, np
procedure(MPI_User_function) :: reduce_sum_real16
type(MPI_Op) :: mysum
integer :: i
call MPI_Init()
call MPI_Comm_rank(MPI_COMM_WORLD,me)
call MPI_Comm_size(MPI_COMM_WORLD,np)
output = 0.0
input = 1.0*me
call MPI_Op_create(reduce_sum_real16,.true.,mysum)
call MPI_Allreduce(input,output,n,MPI_REAL16,mysum,MPI_COMM_WORLD)
error = 0.0
do i = 1,n
error = error + (output(i)-1.0*np)
enddo
if (error.gt.0.0) then
print*,'SAD PANDA = ',error
call MPI_Abort(MPI_COMM_SELF,1)
endif
call MPI_Op_free(mysum)
call MPI_Finalize()
end program test_reduce_sum_real16
使用英特尔16 Fortran编译器和MPICH 3.2+,该程序将无错误返回。显然我没有正确使用I/O,所以我对程序正确性的信心不如我可以将所有结果写入stdout的信心。
关于fortran - MPI_AllReduce的奇怪结果为16字节实数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33109040/