如何在Fortran中执行整数log2()?

时间:2015-11-19 16:08:43

标签: performance fortran bit-manipulation fortran90 logarithm

这样做的一个显而易见的方法如下:

integer function log2_i(val) result(res)
    implicit none
    integer, intent(IN) :: val

    if (val<0) then
        print *, "ERROR in log2_i(): val cannot be negative."
    else if (val==0) then
        print *, "ERROR in log2_i(): todo: return the integer equivalent of (-inf)..."
    else if (val==1) then
        res = 0
    else
        res = FLOOR( LOG(val+0.0d0)/LOG(2.0d0) )
    endif
end function log2_i

使用Fortran的位移操作符有更好的方法吗?

This question几乎相同,但使用无符号整数。不幸的是,符号位将禁止使用相同的算法。

1 个答案:

答案 0 :(得分:5)

正如@harold所提到的,这不应该是一个问题:由于对数仅定义为正数,因此符号位始终为零(参见相应的Wikipedia article)。因此,linked answer中的算法可以直接移植到Fortran(2008 Standard):

module mod_test
contains
  function ilog2_b(val ) result( res )
    integer, intent(in) :: val
    integer             :: res
    integer             :: tmp

    res = -1 
    ! Negativ values not allowed
    if ( val < 1 ) return

    tmp = val
    do while (tmp > 0)
      res = res + 1
      tmp = shiftr( tmp, 1 )
    enddo
  end function
end module

program test
  use mod_test
  print *,'Bitshifting: ', ilog2_b(12345)
  print *,'Formula:     ', floor( log(real(12345) ) / log(2.) )
end program

这是基于@agentp建议的Fortran 95内在BTEST的解决方案:

module mod_test
contains
  function ilog2_b2(val ) result( res )
    integer, intent(in) :: val
    integer             :: res
    integer             :: i

    res = -1 
    ! Negativ values not allowed
    if ( val < 1 ) return
    do i=bit_size(val)-1,0,-1
      if ( btest(val, i) ) then
        res = i
        return
      endif
    enddo

  end function
end module

program test
  use mod_test
  print *,'Testing bits:', ilog2_b2(123456)
  print *,'Formula:     ', floor( log(real(123456) ) / log(2.) )
end program

感谢@IanH指出我bit_size ... 如果您的编译器支持shiftr,我会使用第一个变体。

@IanH提到了另一种使用leadz的方法,这是一个Fortran 2008功能:

module mod_test
contains
  function ilog2_b3(val ) result( res )
    integer, intent(in) :: val
    integer             :: res

    res = -1 
    ! Negativ values not allowed
    if ( val < 1 ) return

    res = bit_size(val)-leadz(val)-1
  end function
end module

program test
  use mod_test
  print *,'Testing bits:', ilog2_b3(123456)
  print *,'Formula:     ', floor( log(real(123456) ) / log(2.) )
end program