Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何以可移植的方式保持Fortran MPI程序的精度?_Fortran_Mpi_Precision - Fatal编程技术网

如何以可移植的方式保持Fortran MPI程序的精度?

如何以可移植的方式保持Fortran MPI程序的精度?,fortran,mpi,precision,Fortran,Mpi,Precision,我有一个Fortran程序,其中我指定了数值数据类型的种类,试图保持最低的精度水平,而不管使用什么编译器来构建程序。例如: integer, parameter :: rsp = selected_real_kind(4) ... real(kind=rsp) :: real_var program main use mpi implicit none integer, parameter :: rsp = selected_real_kind(16) integ

我有一个Fortran程序,其中我指定了数值数据类型的
种类
,试图保持最低的精度水平,而不管使用什么编译器来构建程序。例如:

integer, parameter :: rsp = selected_real_kind(4)
...
real(kind=rsp) :: real_var
program main

   use mpi

   implicit none

   integer, parameter :: rsp = selected_real_kind(16)
   integer :: err
   integer :: rank

   real(rsp) :: real_var

   call MPI_Init(err)
   call MPI_Comm_rank(MPI_COMM_WORLD,rank,err)

   if (rank.eq.0) then
      real_var = 1.123456789012345
      call MPI_Send(real_var,storage_size(real_var)/8,MPI_BYTE,1,5,MPI_COMM_WORLD,err)
   else
      call MPI_Recv(real_var,storage_size(real_var)/8,MPI_BYTE,0,5,MPI_COMM_WORLD,&
         MPI_STATUS_IGNORE,err)
   end if

   print *, rank, real_var

   call MPI_Finalize(err)

end program main
问题是我使用了MPI来并行化代码,我需要确保MPI通信以相同的精度指定相同的类型。我使用以下方法与我的计划中的方法保持一致:

call MPI_Type_create_f90_real(4,MPI_UNDEFINED,rsp_mpi,mpi_err)
...
call MPI_Send(real_var,1,rsp_mpi,dest,tag,MPI_COMM_WORLD,err)
然而,我发现这个MPI例程对于不同的MPI实现并没有得到很好的支持,所以它实际上使我的程序不可移植。如果我省略了
MPI\u Type\u create
例程,那么我就只能依赖标准的
MPI\u REAL
MPI\u DOUBLE\u PRECISION
数据类型,但是如果该类型与
selected\u REAL\u kind
选择的真正类型不一致怎么办?我是否仅仅使用了数据类型的标准
real
声明,没有
kind
属性?如果我这样做,我是否可以保证
MPI\u real
real
始终具有相同的精度,而不管编译器和机器是什么

更新:

我创建了一个简单的程序,演示了当我的内部实数的精度高于
MPI\u DOUBLE\u precision
类型所提供的精度时我所看到的问题:

program main

   use mpi

   implicit none

   integer, parameter :: rsp = selected_real_kind(16)
   integer :: err
   integer :: rank

   real(rsp) :: real_var

   call MPI_Init(err)
   call MPI_Comm_rank(MPI_COMM_WORLD,rank,err)

   if (rank.eq.0) then
      real_var = 1.123456789012345
      call MPI_Send(real_var,1,MPI_DOUBLE_PRECISION,1,5,MPI_COMM_WORLD,err)
   else
      call MPI_Recv(real_var,1,MPI_DOUBLE_PRECISION,0,5,MPI_COMM_WORLD,&
         MPI_STATUS_IGNORE,err)
   end if

   print *, rank, real_var

   call MPI_Finalize(err)

end program main
如果我使用2个内核构建和运行,我会得到:

       0   1.12345683574676513672      
       1   4.71241976735884452383E-3998
现在将16英寸更改为15英寸
选定的\u real\u kind
,我得到:

       0   1.1234568357467651     
       1   1.1234568357467651  

无论使用何种机器/编译器进行构建,使用
selected\u real\u kind(15)
MPI\u DOUBLE\u PRECISION
总是安全的吗

这不是一个真正的答案,但我们也有同样的问题,并使用类似的方法:

!> Number of digits for single precision numbers
integer, parameter, public :: single_prec = 6
!> Number of digits for double precision numbers
integer, parameter, public :: double_prec = 15
!> Number of digits for extended double precision numbers
integer, parameter, public :: xdble_prec = 18
!> Number of digits for quadruple precision numbers
integer, parameter, public :: quad_prec = 33

integer, parameter, public :: rk_prec = double_prec

!> The kind to select for default reals
integer, parameter, public :: rk = selected_real_kind(rk_prec)
然后有一个初始化例程,我们在其中执行:

!call mpi_type_create_f90_real(rk_prec, MPI_UNDEFINED, rk_mpi, iError)
!call mpi_type_create_f90_integer(long_prec, long_k_mpi, iError)
! Workaround shitty MPI-Implementations.
select case(rk_prec)
case(single_prec)
  rk_mpi = MPI_REAL
case(double_prec)
  rk_mpi = MPI_DOUBLE_PRECISION
case(quad_prec)
  rk_mpi = MPI_REAL16
case default
  write(*,*) 'unknown real type specified for mpi_type creation'
end select
long_k_mpi = MPI_INTEGER8
虽然这并不好,但它工作得相当好,似乎可以在Cray、IBMBlueGene和传统的Linux集群上使用。 最好的办法是推动站点和供应商在MPI中正确支持这一点。据我所知,它已在OpenMPI中修复,并计划在3.1.1中在MPICH中修复。请参阅OpenMPI票证和以及MPICH票证和。

如何:

integer, parameter :: DOUBLE_PREC = kind(0.0d0)
integer, parameter :: SINGLE_PREC = kind(0.0e0)

integer, parameter :: MYREAL = DOUBLE_PREC


if (MYREAL .eq. DOUBLE_PREC) then
   MPIREAL = MPI_DOUBLE_PRECISION
else if (MYREAL .eq. SINGLE_PREC) then
   MPIREAL = MPI_REAL
else
   print *, "Erorr: Can't figure out MPI precision."
   STOP
end if

从那时起,使用MPI\u双精度而不是MPI\u双精度。

使用Fortran 2008内部
存储大小来确定每个数字所需的字节数并作为字节发送。请注意,
STORAGE\u SIZE
返回以位为单位的大小,因此需要除以8才能获得以字节为单位的大小

此解决方案适用于移动数据,但不能帮助您使用数据缩减。为此,您必须实现用户定义的缩减操作。如果这对你很重要,我会用细节更新我的答案

例如:

integer, parameter :: rsp = selected_real_kind(4)
...
real(kind=rsp) :: real_var
program main

   use mpi

   implicit none

   integer, parameter :: rsp = selected_real_kind(16)
   integer :: err
   integer :: rank

   real(rsp) :: real_var

   call MPI_Init(err)
   call MPI_Comm_rank(MPI_COMM_WORLD,rank,err)

   if (rank.eq.0) then
      real_var = 1.123456789012345
      call MPI_Send(real_var,storage_size(real_var)/8,MPI_BYTE,1,5,MPI_COMM_WORLD,err)
   else
      call MPI_Recv(real_var,storage_size(real_var)/8,MPI_BYTE,0,5,MPI_COMM_WORLD,&
         MPI_STATUS_IGNORE,err)
   end if

   print *, rank, real_var

   call MPI_Finalize(err)

end program main
我确认此更改纠正了问题,我看到的输出是:

   0   1.12345683574676513672      
   1   1.12345683574676513672  

我使用的代码将其工作精度定义为
wp=selected\u real\u kind(14,40)
,然后在MPI调用中使用
MPI\u DOUBLE\u precision
。据我所知,它没有问题。我添加了一个简单的例子,说明我需要避免什么问题。所以我想知道,如果我明确定义它们的
种类
,我的
real
s是否总是与
MPI\u DOUBLE\u精度
兼容?最后我检查了一下,使用16表示四精度(因此是-3998范围),它不应该与
MPI\u DOUBLE\u精度
兼容。只要使用7到15(包括7到15),就可以使用
MPI\u DOUBLE\u PRECISION
。是的,你是对的。但是
MPI\u DOUBLE\u PRECISION
是否总是意味着无论系统/编译器如何,MPI通信的精度都保持在7到15位之间?换句话说,如果我将我的
real
s指定为14位精度,然后使用
MPI\u DOUBLE\u precision
进行MPI通信,我是否需要担心得到像我发布的那样的结果,即数字在接收端显示为垃圾?除非使用
选定的\u real\u kind
,您可以
使用ISO_FORTRAN_ENV
并使用类型
real32
real64
(位数)可移植地指定单精度和双精度实数。您是对的,我的代码使用OpenMPI 1.4.3运行良好,但使用MPICH时出现问题。我想我最终还是会使用默认的MPI Fortran数据类型,而不是尝试手动设置精度。