2015-11-19 29 views
2

一個明顯的方法,這樣做將是以下幾點:如何在Fortran中執行整數log2()?

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語言的bitshifting運營商更好的辦法?

This question幾乎相同,但使用無符號整數。不幸的是,符號位會禁止使用相同的算法。

+2

在非負操作數RSHIFT相當於一個邏輯右移,所以不看任何問題 – harold

+0

看看標準函數'ILEN',它應該非常接近你所需要的(+/- 1)。 – njuffa

+0

@njuffa這是HPF內在的,而不是Fortran呢?所以它可能得不到廣泛的支持。 – francescalus

回答

5

正如@harold所提到的,這不應該是一個問題:由於對數只是爲正數定義的,因此符號位始終爲零(請參閱相應的Wikipedia article)。因此,在linked answer該算法可直接移植到的Fortran(2008標準):

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 

這是基於所述的Fortran 95內BTEST的溶液通過@agentp的建議:

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