How do Fortran and MPI_Reduce deal with integer overflow?

久未见 提交于 2019-12-12 04:33:58

问题


Following this thread, I want to cast a single / double precision real number "AA" into an integer "II" to compute the checksum of a distributed variable.

Following comments, I have used the intrinsic 'transfer' and rewritten completely this post. Below is a small fortran module that can be used to compute checksums of distributed arrays which depends on the library 2DECOMP&FFT. The module seems to work on my workstation (gfortran 4.9.2, openmpi 1.6.5, 4 processors). Any comment / remark that may improve the portability of the code will be highly appreciated. Main question regarding portability is: do fortran and MPI_reduce deal with integer overflow in the same way according to standards?

module checksum

   use MPI
   use decomp_2d, only : mytype, nrank, &
   xsize, ysize, zsize, &
   transpose_x_to_y, transpose_y_to_z, &
   transpose_z_to_y, transpose_y_to_x

   implicit none

   private ! Make everything private unless declared public

   real(mytype), parameter :: xx=1.

   integer, parameter, public :: chksum_size = size(transfer(xx,(/0,0/)))

   integer, dimension(chksum_size) :: chkr1, chkr2, chkr3

   logical, save :: chksum_is_working

   ! Temporary work variables / arrays
   integer :: code
   integer, dimension(chksum_size) :: tmprchk

   public :: init_chksum, chksum, equal_chksum

   contains

   !
   ! Function to compute the checksum of a real 3D array var
   !
   function chksum(var,nx,ny,nz)
      integer, intent(in) :: nx, ny, nz
      real(mytype), dimension(nx,ny,nz), intent(in) :: var
      integer, dimension(chksum_size) :: chksum

      tmprchk = sum(transfer(var,(/0,0/)))
      call MPI_ALLREDUCE(tmprchk,chksum,chksum_size,MPI_INTEGER,MPI_SUM,MPI_COMM_WORLD,code)

   end function chksum

   !
   ! Subroutine to make sure input arrays have the same checksum
   ! First / second / third array are in X / Y / Z pencil
   ! If switch is provided, reference array is var3.
   !    Otherwise, reference array is var1
   !
   subroutine equal_chksum(var1, var2, var3, switch)
      real(mytype), dimension(xsize(1),xsize(2),xsize(3)), intent(inout) :: var1
      real(mytype), dimension(ysize(1),ysize(2),ysize(3)), intent(inout) :: var2
      real(mytype), dimension(zsize(1),zsize(2),zsize(3)), intent(inout) :: var3
      logical, optional, intent(in) :: switch

      if (chksum_is_working) then ! compute checksums
         chkr1 = chksum(var1,xsize(1),xsize(2),xsize(3))
         chkr2 = chksum(var2,ysize(1),ysize(2),ysize(3))
         chkr3 = chksum(var3,zsize(1),zsize(2),zsize(3))
      else ! generate checksums
         chkr1 = 1
         chkr2 = 2
         chkr3 = 3
      endif

      if (present(switch)) then
         if (any(chkr3.ne.chkr2)) call transpose_z_to_y(var3,var2)
         if (any(chkr3.ne.chkr1)) call transpose_y_to_x(var2,var1)
      else
         if (any(chkr1.ne.chkr2)) call transpose_x_to_y(var1,var2)
         if (any(chkr1.ne.chkr3)) call transpose_y_to_z(var2,var3)
      endif

   end subroutine equal_chksum

   !
   ! Subroutine used to check we have a working checksum
   !
   subroutine init_chksum(var1,var2,var3)
      real(mytype), dimension(xsize(1),xsize(2),xsize(3)), intent(out) :: var1
      real(mytype), dimension(ysize(1),ysize(2),ysize(3)), intent(out) :: var2
      real(mytype), dimension(zsize(1),zsize(2),zsize(3)), intent(out) :: var3

      ! Same random data inside all arrays
      call random_number(var1)
      call transpose_x_to_y(var1,var2)
      call transpose_y_to_z(var2,var3)

      ! Compute checksums
      chkr1 = chksum(var1,xsize(1),xsize(2),xsize(3))
      chkr2 = chksum(var2,ysize(1),ysize(2),ysize(3))
      chkr3 = chksum(var3,zsize(1),zsize(2),zsize(3))

      ! Check checksums
      if (any(chkr1.ne.chkr2).or.any(chkr1.ne.chkr3)) then
         chksum_is_working = .false.
         if (nrank.eq.0) print *,'Checksums based on integer overflow do not work'
      else
         chksum_is_working = .true.
      endif

   end subroutine init_chksum

end module checksum

回答1:


do fortran and MPI_reduce deal with integer overflow in the same way according to standards?

Neither the Fortran standard nor the MPI 3.0 standard even mentions integer overflow so you are at the mercy of the implementers.

However, I see you are only using integers of default kind, use a larger integer kind for intermediate results and you can implement your own overflow detection.




回答2:


Integer overflow is not defined by the Fortran standard. In C signed integer overflow is undefined behaviour.

If you enable undefined behaviour santizations in gfortran, your program will be stopped with an error message. (Happened to me when I was using a 3rd party random number generator.)

You can perform the operation using larger integers and crop the result or call a C function which uses unsigned integers. Integer overflow is only well defined for signed integers.



来源:https://stackoverflow.com/questions/40543931/how-do-fortran-and-mpi-reduce-deal-with-integer-overflow

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!