Lars
Lars

Reputation: 183

Calculating a checksum of a real array in Fortran

I have a large array in Fortran:

real, dimension(N) :: arr

And I need to check if the array is exactly the same in different runtimes of the program. To do this, I wanted to create a checksum of the array to compare. However, I don't know which algorithm to implement. I have looked at Flether's and Adler's algorithm, but have trouble reading the C syntax provided in the examples I found. And also, I don't know how to implement them with Reals instead of chars/integers.

In the C implementations I have found they return:

return (b << 16) | a;

But I don't know how to implement the b << 16 part in Fortran, or if this translates well to reals.

Upvotes: 3

Views: 648

Answers (2)

gordon
gordon

Reputation: 51

A modified version of Lars accomplishes the same without a large temporary array. Also, in Fortran, initializing the variable at declaration time implies the "save" attribute, which is not desirable in this case.

    function hash_real_asz(var,size_var) result(hash)
      implicit none
      integer(8) :: hash
      real(8), dimension(*), intent(in) :: var
      integer, intent(in) :: size_var
      integer(4) :: a,b,i,j
      integer(4), parameter :: mod_adler = 65521
      integer(4), allocatable :: tmp(:)

      a = 1
      b = 0

      do i= 1, size_var
        tmp = transfer(var(i), [0]) ! tmp will be an integer array sufficient to hold var(i)
        do j = 1,size(tmp)
            a = MOD(a+tmp(j), mod_adler) 
            b = MOD(b+a, mod_adler)
        end do
      end do

      hash = ior(b * 65536, a)

    end function

Upvotes: 0

Lars
Lars

Reputation: 183

I finally solved the issue by implementing Adler-32 in Fortran:

subroutine test_hash(var)
  implicit none
  real, dimension(N), intent(in) :: var
  integer, dimension(N) :: int_var
  integer :: a=1, b=0, i=1, mod_adler=65521, hash = 0

  int_var = TRANSFER(var, a, nijk)

  do i= 1, NIJK
    a = MOD(a + int_var(i), mod_adler)
    b = MOD(b+a, mod_adler)
  end do

  hash = ior(b * 65536, a)

  print*, hash

end subroutine test_hash

I ended up using the Fortran intrinsic Transfer function to convert the 32bit reals to 32bit integers, since that's what the algorithm relies on. After this I perform the standard loop. Use the IOR function as suggested by @VladimirF and represented the b<<16 as b * 65536 described by @ja72. Finally I'll be able to print the hash to the console.

The reason for implementing it this way was because it's faster in use than opening a file, computing the checksum per file. The main reason for this is because there are many variables I need to check which switch often since I'm only using this for debugging purposes.

Upvotes: 2

Related Questions