如果B
到一些固定尺寸的预分配是不可取的,我们可以模拟动态数组通过使用可分配数组的自动重新分配。在最简单的情况下,我们可以通过添加一个新值来逐个扩展B
。例如,假设我们在m
和j
上有双循环,选择符合给定条件的值,并将tho值添加到B
。这里,B
的大小自动从0,1,2 ......增加。
integer, allocatable :: B(:)
integer :: m, j
allocate(B(0)) !! start from an empty array
do m = 1, 10000
do j = 1, 10000
!! Some condition to add an element, e.g.
if (m == j .and. mod(m, 1000) == 0) then
!! Add a new element to B.
B = [ B, m ]
endif
enddo
enddo
print *, "size(B) = ", size(B)
print *, B(:)
结果成为
size(B) = 10
1000 2000 3000 4000 5000 6000 7000 8000 9000 10000
你的情况,你也许可以添加类似的方式A
的期望值,例如
allocate(B(0))
do m = 1, ...
do j = 1, ...
do k = 1, ...
if (A(rowin(m)+j, k) < 0.d0) then !! or any condition
B = [ B, A(rowin(m)+j,k) ]
end if
enddo
enddo
enddo
的缺点这种方法的是因为B
每次重新分配新元素时效率非常低ent被添加。虽然这对小B
没有问题,但对于大B
,它可能会成为一个严重的瓶颈。在这种情况下,可以将B
的大小增加几何,而不是增加1.例如,下面的代码根据需要将B
的大小加倍,以减少重新分配的次数。
integer, allocatable :: B(:)
integer :: m, j, nl, p
allocate(B(0)) !! start from an empty array
nl = 0 !! number of elements found
do m = 1, 10000
do j = 1, 10000
if (m == j .and. mod(m, 1000) == 0) then
nl = nl + 1
!! Expand B if the size becomes insufficient.
if (size(B) < nl) B = [ B, (0, p=1,nl) ]
!! Add a new value.
B(nl) = m
endif
enddo
enddo
B = B(1 : nl) !! adjust B to the optimal size
一些更多的注意事项:
- 如果类似的方法被经常使用,可以很方便地编写一个实用程序像
resize()
接受一个分配数组作为参数,并改变其大小。如果效率真的很重要,最好在resize()
中明确使用allocate()
和move_alloc()
来消除一个临时数组。
- 上面的代码需要相对较新的编译器支持左侧的可分配数组的自动重新分配。
- 如果您使用英特尔fortran,则需要添加
-assume realloc_lhs
选项。如果B
的大小可能变得相当大,则还需要-heap-arrays
选项。对于gfortran或Oracle fortran,不需要特殊选项。
- 我们应该不是在左侧附上冒号;即
B(:) = [ B, m ]
是NG
- 关于动态数组(例如增长率)的更多细节,请参见Wiki页。
您真的需要Fortran 90或95还是允许Fortran 2003(自动重新分配答案使用来自Fortran 2003,非常有用)。 –
两者都是可能的(首选Fortran 90/95),但需要处理循环和索引,@roygvib提供了他的答案。 – bosona