0

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
user1824346
  • 575
  • 1
  • 6
  • 17
  • 1
    What do you mean by "cast"? You want to use the same bit pattern rather than value (such as with `transfer`)? – francescalus Nov 11 '16 at 08:32
  • @francescalus thanks, I did not know about transfer, it is exactly what I need. Is it standard / portable? – user1824346 Nov 11 '16 at 08:34
  • 1
    You should anderstand that the word *cast* is ambiguous and you simply MUST explain what exactly you do with some code. For example in C++ there is reinterpret_cast, dynamic_cast, static_cast and more http://stackoverflow.com/questions/332030/when-should-static-cast-dynamic-cast-const-cast-and-reinterpret-cast-be-used We can't tell from a crystal ball which kind of cast you mean. – Vladimir F Героям слава Nov 11 '16 at 10:06
  • @VladimirF reinterpret_cast seems to correspond, question updated – user1824346 Nov 11 '16 at 11:25
  • If you want to sum the bits then are those bits different in an integer than in a float? Note that IBTEST will will tell you if a bit is high or low. – Holmz Nov 11 '16 at 14:18
  • 1
    sems like he edited it into a completely different question – agentp Nov 15 '16 at 12:37
  • Please really do not do this. Do not change existing questions so drastically. Normally I would roll back your edit, but there is an answer to your new question now. – Vladimir F Героям слава Nov 15 '16 at 22:23

2 Answers2

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.

High Performance Mark
  • 77,191
  • 7
  • 105
  • 161
1

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.