在fortran中生成序列数组

问题描述 投票:0回答:4

Fortran 中是否有一个内在函数可以生成一个包含从 a 到 b 的数字序列的数组,类似于 python 的

range()

>>> range(1,5)
[1, 2, 3, 4]
>>> range(6,10)
[6, 7, 8, 9]

fortran fortran90
4个回答
34
投票

不,没有。

但是,您可以使用执行相同操作的构造函数来初始化数组,


program arraycons
  implicit none
  integer :: i
  real :: a(10) = (/(i, i=2,20, 2)/)
  print *, a
end program arraycons


7
投票

如果您需要支持浮点数,这里有一个类似于 NumPy 和 MATLAB 中的

linspace
的 Fortran 子例程。


! Generates evenly spaced numbers from `from` to `to` (inclusive).
!
! Inputs:
! -------
!
! from, to : the lower and upper boundaries of the numbers to generate
!
! Outputs:
! -------
!
! array : Array of evenly spaced numbers
!
subroutine linspace(from, to, array)
    real(dp), intent(in) :: from, to
    real(dp), intent(out) :: array(:)
    real(dp) :: range
    integer :: n, i
    n = size(array)
    range = to - from

    if (n == 0) return

    if (n == 1) then
        array(1) = from
        return
    end if


    do i=1, n
        array(i) = from + range * (i - 1) / (n - 1)
    end do
end subroutine

用途:

real(dp) :: array(5)
call linspace(from=0._dp, to=1._dp, array=array)

输出数组

[0., 0.25, 0.5, 0.75, 1.]

这里

dp

integer, parameter :: dp = selected_real_kind(p = 15, r = 307) ! Double precision

3
投票

可以创建一个函数来精确重现 python 中的 range 功能:

module mod_python_utils
contains
  pure function range(n1,n2,dn_)
     integer,           intent(in) :: n1,n2
     integer, optional, intent(in) :: dn_
     integer, allocatable :: range(:)
     integer ::dn
     dn=1; if(present(dn_))dn=dn_
     if(dn<=0)then
        allocate(range(0))
     else
        allocate(range(1+(n2-n1)/dn))
        range=[(i,i=n1,n2,dn)]
     endif
  end function range
end module mod_python_utils

program testRange
   use mod_python_utils
   implicit none
   integer, allocatable :: v(:)
   v=range(51,70)
   print"(*(i0,x))",v
   v=range(-3,30,2)
   print"(*(i0,x))",v
   print"(*(i0,x))",range(1,100,3)
   print"(*(i0,x))",range(1,100,-3)
end program testRange

上面的输出是

51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
-3 -1 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29
1 4 7 10 13 16 19 22 25 28 31 34 37 40 43 46 49 52 55 58 61 64 67 70 73 76 79 82 85 88 91 94 97 100

注意:

  1. 最后一行是空的:Fortran 慷慨地对待零长度数组。
  2. 分配的变量一旦超出范围就会自动释放。

0
投票

在其他答案的基础上,一个紧凑的类似 linspace 的选项是

program arraycons
  implicit none
  integer :: i
  integer, parameter :: n_step = 5
  real,    parameter :: step_size = 0.1d0
  real :: a(n_step) = (/(i, i=0,n_step-1)/) * step_size
  print *, a
end program arraycons

这对于

n_step
的所有值都按预期工作(0 和负值产生零长度
a
)。对于其他间距,例如对数间距,你可以这样做,例如:

integer, parameter :: start_exponent = -2
real :: a(n_step) = 10.0d0 ** (/(i, i=start_exponent,start_exponent + n_step-1)/)

但要小心日志间距示例:

  • 将 10 写为
    10.0d0
    很重要:如果将其写为整数,则数字的小数部分会丢失,例如
    a = (/0, 0, 1, 10, 100/)
  • 当您在声明时初始化与在代码主体中初始化时,
  • 准确性可能不同,即上面的对数空间代码给出
    a = (/9.9999998E-03, 0.1, 1, 10, 100/)
    ,而当您声明
    a = (/0.01, 0.1, 1, 10, 100/)时,您会得到更准确的
    a
    real :: a(n_step)
    ,然后稍后将其指定为
    a = 10.0d0 ** (/(i, i=start_exponent,start_exponent + n_step-1)/)
© www.soinside.com 2019 - 2024. All rights reserved.