module intmath
      implicit none

      interface ilog2 
      ! log(x)/log(2)
      module procedure ilog2_8
      module procedure ilog2_4
      module procedure ilog2_2
      module procedure ilog2_1
      end interface ilog2

      interface i1log2
      ! log(x+1)/log(2) unless x=maxint, in which case log(x)/log(2)
      module procedure i1log2_8
      module procedure i1log2_4
      module procedure i1log2_2
      module procedure i1log2_1
      end interface i1log2

      contains

      ! ----------------------------------------------------------------

      function i1log2_8(ival)
      implicit none
      integer(kind=8), value :: ival
      integer(kind=8)::i1log2_8
      integer(kind=8), parameter :: one=1
      if(ival+one<ival) then
         i1log2_8=ilog2_8(ival)
      else
         i1log2_8=ilog2_8(ival+one)
      endif
      end function i1log2_8

      ! ----------------------------------------------------------------

      function i1log2_4(ival)
      implicit none
      integer(kind=4), value :: ival
      integer(kind=4)::i1log2_4
      integer(kind=4), parameter :: one=1
      if(ival+one<ival) then
         i1log2_4=ilog2_4(ival)
      else
         i1log2_4=ilog2_4(ival+one)
      endif
      end function i1log2_4

      ! ----------------------------------------------------------------

      function i1log2_2(ival)
      implicit none
      integer(kind=2), value :: ival
      integer(kind=2)::i1log2_2
      integer(kind=2), parameter :: one=1
      if(ival+one<ival) then
         i1log2_2=ilog2_2(ival)
      else
         i1log2_2=ilog2_2(ival+one)
      endif
      end function i1log2_2

      ! ----------------------------------------------------------------

      function i1log2_1(ival)
      implicit none
      integer(kind=1), value :: ival
      integer(kind=1)::i1log2_1
      integer(kind=1), parameter :: one=1
      if(ival+one<ival) then
         i1log2_1=ilog2_1(ival)
      else
         i1log2_1=ilog2_1(ival+one)
      endif
      end function i1log2_1

      ! ----------------------------------------------------------------

      function ilog2_8(i_in)
      implicit none
      integer(kind=8), value :: i_in
      integer(kind=8)::ilog2_8,i
      ilog2_8=0
      i=i_in
      if(i<=0) return
      if(iand(i,i-1)/=0) then
         !write(0,*) 'iand i-1'
         ilog2_8=1
      endif
      if(iand(i,Z'FFFFFFFF00000000')/=0) then
         ilog2_8=ilog2_8+32
         i=ishft(i,-32)
         !write(0,*) 'iand ffffffff',i,ilog2_8
      endif
      if(iand(i,Z'00000000FFFF0000')/=0) then
         ilog2_8=ilog2_8+16
         i=ishft(i,-16)
         !write(0,*) 'iand ffff' ,i,ilog2_8
      endif
      if(iand(i,Z'000000000000FF00')/=0) then
         ilog2_8=ilog2_8+8
         i=ishft(i,-8)
         !write(0,*) 'iand ff',i,ilog2_8
      endif
      if(iand(i,Z'00000000000000F0')/=0) then
         ilog2_8=ilog2_8+4
         i=ishft(i,-4)
         !write(0,*) 'iand f',i,ilog2_8
      endif
      if(iand(i,Z'000000000000000C')/=0) then
         ilog2_8=ilog2_8+2
         i=ishft(i,-2)
         !write(0,*) 'iand c',i,ilog2_8
      endif
      if(iand(i,Z'0000000000000002')/=0) then
         ilog2_8=ilog2_8+1
         i=ishft(i,-1)
         !write(0,*) 'iand 2',i,ilog2_8
      endif
      end function ilog2_8

      ! ----------------------------------------------------------------

      function ilog2_4(i_in)
      implicit none
      integer(kind=4), value :: i_in
      integer(kind=4)::ilog2_4,i
      ilog2_4=0
      i=i_in
      if(i<=0) return
      if(iand(i,i-1)/=0) then
         !write(0,*) 'iand i-1'
         ilog2_4=1
      endif
      if(iand(i,Z'FFFF0000')/=0) then
         ilog2_4=ilog2_4+16
         i=ishft(i,-16)
         !write(0,*) 'iand ffff' ,i,ilog2_4
      endif
      if(iand(i,Z'0000FF00')/=0) then
         ilog2_4=ilog2_4+8
         i=ishft(i,-8)
         !write(0,*) 'iand ff',i,ilog2_4
      endif
      if(iand(i,Z'000000F0')/=0) then
         ilog2_4=ilog2_4+4
         i=ishft(i,-4)
         !write(0,*) 'iand f',i,ilog2_4
      endif
      if(iand(i,Z'0000000C')/=0) then
         ilog2_4=ilog2_4+2
         i=ishft(i,-2)
         !write(0,*) 'iand c',i,ilog2_4
      endif
      if(iand(i,Z'00000002')/=0) then
         ilog2_4=ilog2_4+1
         i=ishft(i,-1)
         !write(0,*) 'iand 2',i,ilog2_4
      endif
      end function ilog2_4

      ! ----------------------------------------------------------------

      function ilog2_2(i_in)
      implicit none
      integer(kind=2), value :: i_in
      integer(kind=2)::ilog2_2,i
      ilog2_2=0
      i=i_in
      if(i<=0) return
      if(iand(i,i-1)/=0) then
         !write(0,*) 'iand i-1'
         ilog2_2=1
      endif
      if(iand(i,Z'FF00')/=0) then
         ilog2_2=ilog2_2+8
         i=ishft(i,-8)
         !write(0,*) 'iand ff',i,ilog2_2
      endif
      if(iand(i,Z'00F0')/=0) then
         ilog2_2=ilog2_2+4
         i=ishft(i,-4)
         !write(0,*) 'iand f',i,ilog2_2
      endif
      if(iand(i,Z'000C')/=0) then
         ilog2_2=ilog2_2+2
         i=ishft(i,-2)
         !write(0,*) 'iand c',i,ilog2_2
      endif
      if(iand(i,Z'0002')/=0) then
         ilog2_2=ilog2_2+1
         i=ishft(i,-1)
         !write(0,*) 'iand 2',i,ilog2_2
      endif
      end function ilog2_2

      ! ----------------------------------------------------------------

      function ilog2_1(i_in)
      implicit none
      integer(kind=1), value :: i_in
      integer(kind=1)::ilog2_1,i
      ilog2_1=0
      i=i_in
      if(i<=0) return
      if(iand(i,i-1)/=0) then
         !write(0,*) 'iand i-1'
         ilog2_1=1
      endif
      if(iand(i,Z'F0')/=0) then
         ilog2_1=ilog2_1+4
         i=ishft(i,-4)
         !write(0,*) 'iand f',i,ilog2_1
      endif
      if(iand(i,Z'0C')/=0) then
         ilog2_1=ilog2_1+2
         i=ishft(i,-2)
         !write(0,*) 'iand c',i,ilog2_1
      endif
      if(iand(i,Z'02')/=0) then
         ilog2_1=ilog2_1+1
         i=ishft(i,-1)
         !write(0,*) 'iand 2',i,ilog2_1
      endif
      end function ilog2_1
      end module intmath
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
c$$$ TEST PROGRAM FOR THIS MODULE
c$$$      program test_intmath
c$$$      use intmath
c$$$      implicit none
c$$$      real(kind=16) :: temp
c$$$      real(kind=16), parameter :: alog2=log(2.0_16)
c$$$      integer(kind=8), parameter  ::                                    &
c$$$     &     one=1,big=Z'7FFFFFFFFFFFFFFF',small=-2000000_8,              &
c$$$     &     check=Z'1FFFFFFF'
c$$$      integer(kind=8) :: ival, iret
c$$$      !$OMP PARALLEL DO PRIVATE(ival,temp,iret)
c$$$      do ival=small,big
c$$$ 10      format(Z16,' -- MISMATCH: ',I0,'=>',I0,' (',I0,' = ',F0.10,')')
c$$$ 20      format(Z16,' -- OKAY:     ',I0,'=>',I0,' (',I0,' = ',F0.10,')')
c$$$         if(ival+one<ival) then
c$$$            temp=log(real(max(ival,one),kind=16))/alog2
c$$$         else
c$$$            temp=log(real(max(ival+one,one),kind=16))/alog2
c$$$         endif
c$$$         iret=i1log2(ival)
c$$$         if(iret/=ceiling(temp) .or. ival==0 .or. ival==check) then
c$$$            !$OMP CRITICAL
c$$$            if(iret/=ceiling(temp)) then
c$$$               print 10, ival, ival, iret,ceiling(temp),temp
c$$$            else
c$$$               print 20, ival, ival, iret,ceiling(temp),temp
c$$$            endif
c$$$            !$OMP END CRITICAL
c$$$         endif
c$$$      enddo
c$$$      !$OMP END PARALLEL DO
c$$$      end program test_intmath