我喜欢fortran的数组切片符号(array(1:n)
),但我想知道如果我在没有必要时使用它们,我是否会受到性能影响。
例如,考虑一下这个简单的快速排序代码(它有效,但很明显它没有注意选择一个好的支点):
recursive subroutine quicksort(array, size)
real, dimension(:), intent(inout) :: array
integer, intent(in) :: size
integer :: p
if (size > 1) then
p = partition(array, size, 1)
call quicksort(array(1:p-1), p-1)
call quicksort(array(p+1:size), size-p)
end if
end subroutine quicksort
function partition(array, size, pivotdex) result(p)
real, dimension(:), intent(inout) :: array
integer, intent(in) :: size, pivotdex
real :: pivot
integer :: i, p
pivot = array(pivotdex)
call swap(array(pivotdex), array(size))
p=1
do i=1,size-1
if (array(i) < pivot) then
call swap(array(i), array(p))
p=p+1
end if
end do
call swap(array(p), array(size))
end function partition
subroutine swap(a, b)
real, intent(inout) :: a, b
real :: temp
temp = a
a = b
b = temp
end subroutine swap
我可以轻松地传递整个数组以及递归部分应该工作的索引,但我喜欢这样的代码。然而,当我调用quicksort(array(1:p-1), p-1)
时,它是否会使一个临时数组进行操作,或者它只是做一个浅的参考结构或类似的东西?这是一个足够有效的解决方案吗?
This question是相关的,但它似乎是因为跨步切片和显式大小的虚拟变量而产生临时数组,所以我对此安全,对吧?
答案 0 :(得分:3)
关于效率问题:是的,对于大多数情况,使用假定形状的数组和数组切片确实是一个足够有效的解决方案。
涉及一些开销。假定形状数组需要数组描述符(有时也称为“dope vector”)。此数组描述符包含有关维度和步幅的信息,设置它需要一些工作。
带有假设形状伪参数的被调用过程中的代码必须考虑统一步幅(通常情况)和非统一步幅。某个地方的某个人可能想要使用somearray(1:100:3)的实际参数来调用你的排序例程,因为他只想对数组的每个第三个元素进行排序。不寻常,但合法。不依赖于统一步幅的代码可能会有一些性能损失。
话虽如此,编译器,尤其是那些使用链接时优化的编译器,现在在内联和/或剥离所有额外工作方面都非常好,并且还倾向于克隆特殊套管统一步骤的程序。
因此,作为一项规则,清晰度(和假设形状数组)应该获胜。请记住,在某些情况下,传递数组参数的传统方式可能会获得一些额外的效率。
答案 1 :(得分:2)
您的子阵列
array(1:p-1)
是连续的,前提是array
是连续的。
此外,您使用假定的形状数组伪参数
real, dimension(:), intent(inout) :: array
没有必要暂时的。只传递假定形状数组的描述符。并且由于您的子阵列是连续的,即使是假定的大小,显式大小,或假定大小为contiguous
属性的伪参数也可以。