在Fortran项目中,我们使用二进制搜索来查找所需的值:
integer function binsearch(tab, el)
implicit none
real, intent(in) :: tab(:), el
integer :: a, b, mid
a = 1
b = size(tab)
do while (b - a > 1)
mid = (a + b)/2
if (el >= tab(mid)) then
a = mid
else
b = mid
endif
! if (el < tab(mid + 1)) exit ! BAD OPTIMIZATION !
enddo
binsearch = a
end function binsearch
稍后我们只是使用它
foo = binsearch(tab, el)
不幸的是,周围的例程被大量使用,BAD OPTIMIZATION
将总执行时间提高了一半。所以我考虑了内联函数来降低通话费用。
是否有可能将此功能标记为内联?在C中有关键字inline
,这是对编译器的建议 - 在Fortran 2008中有这样的东西吗?
为了代码清晰,我不想复制粘贴这个。
这取决于编译器。我可以验证这适用于Cray和英特尔Fortran编译器,但声明略有不同。
Cray编译器:
!dir$ forceinline :: frob
这将强制编译器内联函数frob。您将它放在函数定义的正上方。
Intel编译器:
!dir$ attributes forceinline :: frob
我没有看到gcc / gfortran目前有这些选项。
两个编译器的手册都涵盖了这一点。
在Fortran中,与C中的inline
没有直接的类比;始终由编译器决定哪些函数是内联的。最重要的是编译具有高优化级别的代码以打开积极的内联(例如gfortran中的-Ofast
,ifort中的-fast
)。此外,您可能希望启用“链接时优化”(gfortran中的-flto
,ifort中的-ipo
),以便编译器可以在链接时根据需要内联不同源文件中的函数。
但是,有一些方法可以重写代码,增加内联的机会。一种这样的方法是明确地将函数标记为pure
(即没有副作用的函数),因为这样的含义使编译器更容易优化对它的调用。换一种说法:
pure function binsearch(tab, el) result(r)
real, intent(in) :: tab(:), el
integer :: r, a, b, mid
...
end function
如果你可以将binsearch
重写为你正在使用它的任何函数内的嵌套函数,那么很可能编译将替换函数体对tab
的函数调用或快速的goto
语句,即使你没有更改编译选项。在这种情况下:
subroutine some_other_thing()
...
! Do the search
i = binsearch(tab, el)
...
contains
pure function binsearch(tab, el) result(r)
real, intent(in) :: tab(:), el
integer :: r, a, b, mid
...
end function
end subroutine