MINLOC 是否适用于从索引 0 开始的数组? (Fortran 90/95)
Does MINLOC work for arrays beginning at index 0? (Fortran 90/95)
在使用了一段时间的 C 之后,我又回到了 Fortran 并将我代码中的数组从索引 0 分配到 N:
real(kind=dp), dimension(:), allocatable :: a
allocate(a(0:50))
我需要找到数组的最小绝对值的索引,所以我使用了 MINLOC,为了检查这一点,我将它与 MINVAL 进行了比较:
minloc(abs(a(:)))
minval(abs(a))
MINLOC 的结果是索引 42
但 MINVAL 的结果对应于 41
。这是输出中的相关部分:
Index i a(i)
39 0.04667
40 0.02222
41 0.00222 !This was clearly the minimum value
42 0.02667
MINLOC = 42
MINVAL = 0.00222
我认为这与 Fortran 内在函数没有正确处理索引为 0 的数组有关,因为以这种方式声明数组不是标准的 Fortran 风格(但仍然允许!)。
任何人都可以确认这一点或提供解决方法吗?
您的数组 a
确实从索引 0 开始,但您没有使用它。您至少搜索了数组 abs(a(:))
。这个匿名数组表达式从 1 开始,默认情况下所有数组都是如此。
但即使您使用 a
,结果也会相同,并且与 Fortran 中数组参数传递的工作方式一致。
Fortran 标准明确指出:
The i subscript returned lies in the range 1 to ei , where ei is the
extent of the idimension of ARRAY. If ARRAY has size zero, all
elements of the result are zero.
如果您使用假定的形状参数,则下限不会自动随数组一起传递。例如,如果您有自己的函数
function f(arg)
real :: arg(:)
arg
无论实际参数在调用代码中的何处开始,始终从 1 开始。
您可以将其更改为以其他值开始
function f(arg)
real :: arg(-42:)
它将从该值开始编制索引。
有两种简单的方法可以处理调整从 minloc() 获得的索引的复杂性:一种是简单地为所有索引添加 lbound() - 1,另一种是使用具有基于 1 的索引的数组指针。示例代码可能如下所示:
program test
implicit none
integer, allocatable, target :: a(:,:)
integer, pointer :: anew(:,:)
integer :: loc(2)
allocate( a( 0:4, 2:5 ), source= 10 ) !! make an array filled with 10
a( 2, 3 ) = -700 !! set the minimum value
loc(:) = minloc( a ) !! minloc() receives "a" with 1-based indices
print *, loc(:) !! so we get [3,2]
print *, a( loc(1), loc(2) ) !! 10 (wrong result...)
!! Method (1) : adjust indices manually
loc(:) = loc(:) + lbound( a ) - 1
print *, a( loc(1), loc(2) ) !! -700 (now a correct result)
!! Method (2) : use array pointer with 1-based indices
anew( 1:, 1: ) => a
loc(:) = minloc( anew )
print *, loc(:) !! we get [3,2] again
print *, anew( loc(1), loc(2) ) !! -700 (this time, no need to adjust indices)
end program
在使用了一段时间的 C 之后,我又回到了 Fortran 并将我代码中的数组从索引 0 分配到 N:
real(kind=dp), dimension(:), allocatable :: a
allocate(a(0:50))
我需要找到数组的最小绝对值的索引,所以我使用了 MINLOC,为了检查这一点,我将它与 MINVAL 进行了比较:
minloc(abs(a(:)))
minval(abs(a))
MINLOC 的结果是索引 42
但 MINVAL 的结果对应于 41
。这是输出中的相关部分:
Index i a(i)
39 0.04667
40 0.02222
41 0.00222 !This was clearly the minimum value
42 0.02667
MINLOC = 42
MINVAL = 0.00222
我认为这与 Fortran 内在函数没有正确处理索引为 0 的数组有关,因为以这种方式声明数组不是标准的 Fortran 风格(但仍然允许!)。
任何人都可以确认这一点或提供解决方法吗?
您的数组 a
确实从索引 0 开始,但您没有使用它。您至少搜索了数组 abs(a(:))
。这个匿名数组表达式从 1 开始,默认情况下所有数组都是如此。
但即使您使用 a
,结果也会相同,并且与 Fortran 中数组参数传递的工作方式一致。
Fortran 标准明确指出:
The i subscript returned lies in the range 1 to ei , where ei is the extent of the idimension of ARRAY. If ARRAY has size zero, all elements of the result are zero.
如果您使用假定的形状参数,则下限不会自动随数组一起传递。例如,如果您有自己的函数
function f(arg)
real :: arg(:)
arg
无论实际参数在调用代码中的何处开始,始终从 1 开始。
您可以将其更改为以其他值开始
function f(arg)
real :: arg(-42:)
它将从该值开始编制索引。
有两种简单的方法可以处理调整从 minloc() 获得的索引的复杂性:一种是简单地为所有索引添加 lbound() - 1,另一种是使用具有基于 1 的索引的数组指针。示例代码可能如下所示:
program test
implicit none
integer, allocatable, target :: a(:,:)
integer, pointer :: anew(:,:)
integer :: loc(2)
allocate( a( 0:4, 2:5 ), source= 10 ) !! make an array filled with 10
a( 2, 3 ) = -700 !! set the minimum value
loc(:) = minloc( a ) !! minloc() receives "a" with 1-based indices
print *, loc(:) !! so we get [3,2]
print *, a( loc(1), loc(2) ) !! 10 (wrong result...)
!! Method (1) : adjust indices manually
loc(:) = loc(:) + lbound( a ) - 1
print *, a( loc(1), loc(2) ) !! -700 (now a correct result)
!! Method (2) : use array pointer with 1-based indices
anew( 1:, 1: ) => a
loc(:) = minloc( anew )
print *, loc(:) !! we get [3,2] again
print *, anew( loc(1), loc(2) ) !! -700 (this time, no need to adjust indices)
end program