Fortran 中数组赋值的不同形状
Different shape for array assignment in Fortran
这是我的代码:
Program Arrays
Implicit none
Integer::i,j
Integer,dimension(2)::V_Max
Complex,dimension(0:7,3)::V_cvo
Complex,dimension(7,3)::V_cvo_temp
Do concurrent(i=0:7,j=1:3)
V_cvo(i,j)=cmplx(i+j,2*i-j)
End Do
V_cvo_temp=V_cvo(1:,:)
V_Min=minloc(abs((/((V_cvo_temp(i,j),j=1,3),i=2,5)/)))
Stop
End Program Arrays
编译后我收到一条消息:
Error: Different shape for array assignment on dimension 1 (2 and 1)|
这里有什么问题?如果我想在该数组的特定扇区中的某个数组中找到最小元素的位置,这怎么可能?
这可能是问题的可能解决方案之一:
Program Arrays
Implicit none
Integer::i,j
Integer,dimension(2)::V_Max
Complex,dimension(0:7,2)::V_cvo
Logical,dimension(0:7,2) :: lmask = .FALSE.
forall(i=2:5,j=1:2)lmask(i,j) = .TRUE.
Do concurrent(i=0:7,j=1:2)
V_cvo(i,j)=cmplx(i+j,2*i-j)
End Do
V_Max = Maxloc(abs(V_cvo),mask=lmask)-(/1,0/)
Open(1,File='Output.txt',Status='Unknown')
Write(1,'(2x,i0,2x,i0)') V_max
Write(1,*)
Do concurrent(i=2:5,j=1:2)
Write(1,'(1x,i0,1x,i0,2x,f7.4)')i,j,abs(V_cvo(i,j))
End Do
Close(1)
Stop
End Program Arrays
输出文件为:
5 1
2 1 4.2426
3 1 6.4031
4 1 8.6023
5 1 10.8167
2 2 4.4721
3 2 6.4031
4 2 8.4853
5 2 10.6301
对此有何看法?
右边好像是
V_Min=minloc(abs((/((V_cvo_temp(i,j),j=1,3),i=2,5)/)))
returns 一个标量而不是 2 个分量的向量。你需要的是 array slicing: V_cvo_temp(1:3,2:5)
V_Min=minloc(abs(V_cvo_temp(2:5,1:3)))
或更简单
V_Min=minloc(abs(V_cvo(2:5,1:3))) ! without temp array
另外你不需要最后的stop
。
编辑 1:
minloc
returns 相对于 (1,1) 的索引。要了解此行为,请尝试以下示例:
Program Hello
Implicit none
Integer,dimension(2)::V_Min
Complex,dimension(0:7,3)::V_cvo
V_cvo = cmplx(10,10)
V_cvo(3,2) = cmplx(0,0) ! the minimum index = [3,2]
V_Min=minloc(abs(V_cvo))
print *, 'minloc for whole array: ', V_Min
V_Min=minloc(abs(V_cvo(3:,2:)))
print *, 'minloc for sub-array: ', V_Min
End Program Hello
它输出:
minloc for whole array: 4 2 ! base index=[-1,0]
minloc for sub-array: 1 1 ! base index=[2,2]
因此,如果将子数组传递给 minloc,您需要添加基本索引以获得 'correct' 答案。
这个表达式
minloc(abs((/((V_cvo_temp(i,j),j=1,3),i=2,5)/)))
returns 具有 1 个元素的 rank-1 数组。作业的 lhs 是一个包含 2 个元素的 rank-1 数组。 Fortran 不会分配不兼容的数组——因此会出现编译器错误消息。
(@gdlmx 的回答在其诊断中有细微的错误,如果表达式 returned 标量 Fortran 会愉快地将其值广播到数组的每个元素。)
如果表达式 return 一个标量,它仍然不会 return V_cvo
的那个部分中的最小元素的位置。子表达式
(/((V_cvo_temp(i,j),j=1,3),i=2,5)/)
生成包含 V_cvo_temp
的指定元素的 rank-1 数组,它实质上将数组展平为向量并在此过程中丢失它们的位置。这就是为什么第一个表达式 return 是具有 1 个元素的 rank-1 数组 - 它是 rank-1 数组中元素的位置。
这个解决方案的问题
V_Min=minloc(abs(V_cvo(2:5,1:3)))
是表达式 abs(V_cvo(2:5,1:3))
将 return 索引的(临时)数组,因为默认情况下 Fortran 数组从每个等级的 1 开始。当我尝试代码时,它 return 的位置 (1,1)
似乎在所考虑的部分之外。那就是临时数组的最小元素所在的位置。
我尝试过的 'clever' 解决方案的问题是 abs(V_cvo(2:5,1:3))
总是 returns,即使从视图中隐藏,每个等级从 1 开始索引的临时数组. minloc
或类似函数的任何应用程序都使用这些索引,而不是 v_cvo
使用的索引。最好的解决方案可能是像这样制作一个显式临时数组(适当声明):
allocate(abstemp(LBOUND(v_cvo,1):UBOUND(v_cvo,1),LBOUND(v_cvo,2):UBOUND(v_cvo,2)))
然后
v_min = minloc(abstemp(2:5,1:3))
和
deallocate(abstemp)
这个解决方案也可以正常工作(也许最好):
forall(i=1:7,j=1:3) V_cvo_temp(i,j)=abs(V_cvo(i,j))
V_Min = MINLOC(V_cvo_temp(m:n,:))+(/m-1,0/)
代码对于每个 m 和 n 都是正确的,如果它们在这种情况下的间隔 1:7 或其他间隔中。
这是我的代码:
Program Arrays
Implicit none
Integer::i,j
Integer,dimension(2)::V_Max
Complex,dimension(0:7,3)::V_cvo
Complex,dimension(7,3)::V_cvo_temp
Do concurrent(i=0:7,j=1:3)
V_cvo(i,j)=cmplx(i+j,2*i-j)
End Do
V_cvo_temp=V_cvo(1:,:)
V_Min=minloc(abs((/((V_cvo_temp(i,j),j=1,3),i=2,5)/)))
Stop
End Program Arrays
编译后我收到一条消息:
Error: Different shape for array assignment on dimension 1 (2 and 1)|
这里有什么问题?如果我想在该数组的特定扇区中的某个数组中找到最小元素的位置,这怎么可能?
这可能是问题的可能解决方案之一:
Program Arrays
Implicit none
Integer::i,j
Integer,dimension(2)::V_Max
Complex,dimension(0:7,2)::V_cvo
Logical,dimension(0:7,2) :: lmask = .FALSE.
forall(i=2:5,j=1:2)lmask(i,j) = .TRUE.
Do concurrent(i=0:7,j=1:2)
V_cvo(i,j)=cmplx(i+j,2*i-j)
End Do
V_Max = Maxloc(abs(V_cvo),mask=lmask)-(/1,0/)
Open(1,File='Output.txt',Status='Unknown')
Write(1,'(2x,i0,2x,i0)') V_max
Write(1,*)
Do concurrent(i=2:5,j=1:2)
Write(1,'(1x,i0,1x,i0,2x,f7.4)')i,j,abs(V_cvo(i,j))
End Do
Close(1)
Stop
End Program Arrays
输出文件为:
5 1
2 1 4.2426
3 1 6.4031
4 1 8.6023
5 1 10.8167
2 2 4.4721
3 2 6.4031
4 2 8.4853
5 2 10.6301
对此有何看法?
右边好像是
V_Min=minloc(abs((/((V_cvo_temp(i,j),j=1,3),i=2,5)/)))
returns 一个标量而不是 2 个分量的向量。你需要的是 array slicing: V_cvo_temp(1:3,2:5)
V_Min=minloc(abs(V_cvo_temp(2:5,1:3)))
或更简单
V_Min=minloc(abs(V_cvo(2:5,1:3))) ! without temp array
另外你不需要最后的stop
。
编辑 1:
minloc
returns 相对于 (1,1) 的索引。要了解此行为,请尝试以下示例:
Program Hello
Implicit none
Integer,dimension(2)::V_Min
Complex,dimension(0:7,3)::V_cvo
V_cvo = cmplx(10,10)
V_cvo(3,2) = cmplx(0,0) ! the minimum index = [3,2]
V_Min=minloc(abs(V_cvo))
print *, 'minloc for whole array: ', V_Min
V_Min=minloc(abs(V_cvo(3:,2:)))
print *, 'minloc for sub-array: ', V_Min
End Program Hello
它输出:
minloc for whole array: 4 2 ! base index=[-1,0]
minloc for sub-array: 1 1 ! base index=[2,2]
因此,如果将子数组传递给 minloc,您需要添加基本索引以获得 'correct' 答案。
这个表达式
minloc(abs((/((V_cvo_temp(i,j),j=1,3),i=2,5)/)))
returns 具有 1 个元素的 rank-1 数组。作业的 lhs 是一个包含 2 个元素的 rank-1 数组。 Fortran 不会分配不兼容的数组——因此会出现编译器错误消息。
(@gdlmx 的回答在其诊断中有细微的错误,如果表达式 returned 标量 Fortran 会愉快地将其值广播到数组的每个元素。)
如果表达式 return 一个标量,它仍然不会 return V_cvo
的那个部分中的最小元素的位置。子表达式
(/((V_cvo_temp(i,j),j=1,3),i=2,5)/)
生成包含 V_cvo_temp
的指定元素的 rank-1 数组,它实质上将数组展平为向量并在此过程中丢失它们的位置。这就是为什么第一个表达式 return 是具有 1 个元素的 rank-1 数组 - 它是 rank-1 数组中元素的位置。
这个解决方案的问题
V_Min=minloc(abs(V_cvo(2:5,1:3)))
是表达式 abs(V_cvo(2:5,1:3))
将 return 索引的(临时)数组,因为默认情况下 Fortran 数组从每个等级的 1 开始。当我尝试代码时,它 return 的位置 (1,1)
似乎在所考虑的部分之外。那就是临时数组的最小元素所在的位置。
我尝试过的 'clever' 解决方案的问题是 abs(V_cvo(2:5,1:3))
总是 returns,即使从视图中隐藏,每个等级从 1 开始索引的临时数组. minloc
或类似函数的任何应用程序都使用这些索引,而不是 v_cvo
使用的索引。最好的解决方案可能是像这样制作一个显式临时数组(适当声明):
allocate(abstemp(LBOUND(v_cvo,1):UBOUND(v_cvo,1),LBOUND(v_cvo,2):UBOUND(v_cvo,2)))
然后
v_min = minloc(abstemp(2:5,1:3))
和
deallocate(abstemp)
这个解决方案也可以正常工作(也许最好):
forall(i=1:7,j=1:3) V_cvo_temp(i,j)=abs(V_cvo(i,j))
V_Min = MINLOC(V_cvo_temp(m:n,:))+(/m-1,0/)
代码对于每个 m 和 n 都是正确的,如果它们在这种情况下的间隔 1:7 或其他间隔中。