【问题标题】:Passing array length to function将数组长度传递给函数
【发布时间】:2021-07-19 08:59:05
【问题描述】:

如果这是一个微不足道的问题,我很抱歉。我的fortran-fu很差。

在 Fortran 中有没有办法传递数组长度?使用common(据我所知,它相当于global)也是一种选择。我想要的是在主程序中调用带有数组的函数。例如(这是输入的,不是从任何地方复制粘贴的)

program prog
integer num
double precision x(num),v
double precision test

....
v=test(x,num)
....


function test(x,num)
double precision test
integer num
double precision x(num)
test=0.0d0
....
return
end

这不会编译,因为num 不是常量。重要的是要知道我传递的数组大小是多少。

编辑:我使用的是 GNU Fortran 95 编译器。

Edit2:我尝试了高性能标记的解决方案,但没有运气:

  program prog
  integer v
  parameter (v=10)
  double precision x(v),test,k
  k=test(x)
  write (*,*) size(x)
  stop
  end

  function test(x)
  double precision, dimension(:),intent(in) :: x
  double precision test
  write (*,*) size(x)
  test = 0.0d0
  return
  end
  

输出应该是写入 10 的两行。相反,我得到了这个:

/scpc:niels: #$ f95 err.f
/scpc:niels: #$ ./a.out 
           0
          10
/scpc:niels: #$ 

【问题讨论】:

  • 常见块之外的另一种样式。没有理由在“结束”之前使用“停止”或“返回”。 double precision 应该避免并改为real(rp),其中rp 可能是rp=kind(1d.0),或者您使用selected_real_kind。另外,缩进旅游代码!
  • @VladimirF 谢谢你们的cmets。我使用与 Emacs 相同的缩进。作为您的其他四个 cmets,我正在更新我的 adivsor 代码并且我的 fortran-fu 很低。我怀疑如果我尝试这样做的话,我会造成更多的伤害。

标签: fortran gfortran


【解决方案1】:

Fortran 数组“知道”它们有多长,您不需要将数组及其长度作为不同的参数传递。 (除非,也就是说,你正在与旧的 Fortran 代码交互。)今天你会写这样的东西

function test(arr)
    real, dimension(:), intent(in) :: arr
    ...
    integer :: arrsize
    ...
    arrsize = size(arr)
    ...

如果您必须与传递数组大小的旧代码交互,您可以像这样进行调用

  call old_fortran_subr(array, size(array, 1), other_arguments)

哦,在我写作的时候,在你从头开始编写的任何代码中都与 common 无关,这是 70 年代及更早的(正确地)弃用的功能。而是使用模块变量

【讨论】:

  • +1 仅用于最后一句话。应该避免常见的块,就像任何甚至模糊的现代 Fortran 方言中的瘟疫一样。
  • 我试过这个没有运气。我已经用我所做的编辑了我的问题。我在哪里可以了解模块变量?
  • 我的编译器(Intel Fortran 13.0)编译你的新代码并写出10两次。要么你发布的不是你的代码的忠实副本,要么你有我看不到的问题。
  • @Yotam:您的函数中有一个假定形状的数组 (dimension(:)) 虚拟参数,它需要一个“显式接口”。提供此功能的最简单方法是使您的函数成为程序或您在程序中使用的模块的内部过程。
  • 关于模块变量的主题,虽然它们不如普通变量那么糟糕,但仍尽可能避免使用它们。全局变量使代码的维护和开发更加困难,将变量的范围保持在尽可能小的范围内确实是一种好习惯,从长远来看,它会节省您的时间和精力。
【解决方案2】:

好的,这里发生了很多事情,尤其是您使用的 Fortran 风格有点过时。让我们一步一步来……

首先确保您始终使用隐式无

其次,如果您先验地知道数组的大小,则可以使用符号常量来表示其大小。你可以通过一个参数来做到这一点:

Program prog

  Implicit None ! ALWAYS USE THIS

  Integer, Parameter :: num = 36

  Double Precision x( num )
  Double Precision test
  Double Precision v

  Call Random_number( x )

  v = test( x, num )

  Write( *, * ) v

End Program prog

Function test( x, num )

  Implicit None ! ALWAYS USE THIS

  Double Precision test

  Integer num
  Double Precision x( num )

  Integer i

  test = 0.0d0
  Do i = 1, num
     test = test + x( i ) * x( i )
  End Do

End Function test
[luser@cromer stackoverflow]$ gfortran -O -std=f95 -Wall -Wextra -pedantic func.f90
[luser@cromer stackoverflow]$ ./a.out
   12.129812171430215     

注意 num 是如何设置为 36 的,但参数位意味着我不能更改它的值 - 它是一个常量,因此可以用来设置数组的大小。

这就是直到 1990 年的情况。然后,语言中出现了许多改变答案的东西。与您的问题最直接相关的是可分配数组,它允许您在运行时指定数组的大小,以及假定的形状数组,这使得将数组传递给子程序更简单。然而,还有很多其他的东西出现了,我建议你看一本书来了解它们——新语言比旧语言更具表现力和安全性。作为一个例子,我现在会把上面的内容写成类似

[luser@cromer stackoverflow]$ cat func.f90

Module numbers_module

  Integer, Parameter :: wp = Selected_real_kind( 12, 70 )

End Module numbers_module

    Module funcs_module

      Use numbers_module

      Implicit None

      Public :: test

      Private

    Contains

      Function test( x ) Result( sum_sq )

        Implicit None ! ALWAYS USE THIS

        Real( wp ) :: sum_sq

        Real( wp ), Dimension( : ), Intent( In ) :: x

        sum_sq = Sum( x * x )

      End Function test

    End Module funcs_module

    Program prog

      Use numbers_module
      Use funcs_module

      Implicit None ! ALWAYS USE THIS

      Real( wp ), Dimension( : ), Allocatable :: x 

      Real( wp ) :: v

      Integer :: num

      Write( *, * ) 'How many elements ?'
      Read ( *, * ) num
      Allocate( x( 1:num ) )

      Call Random_number( x )

      v = test( x )

      Write( *, * ) v

    End Program prog

    [luser@cromer stackoverflow]$ gfortran -O -std=f95 -Wall -Wextra -pedantic func.f90
    [luser@cromer stackoverflow]$ ./a.out
     How many elements ?
    39
       14.151818513394156  

如果您决定采用这种方式,请确保您了解为什么要使用此方法,测试的接口需要在调用点的范围内 - 并且要做到这一点,请阅读一本书。

哦。常见的。只是说不。

【讨论】:

    【解决方案3】:

    在早期版本的 Fortran 中使用了隐式变量声明。通过这种方法,可以简单地使用变量而不显式声明它。诸如 IMPLICIT REAL(A-H, O-Z ) 之类的语句将声明所有以字母 A-H 和 O-Z 开头的实变量。这现在被认为过于松散,并且更强大的语言 C 所要求的显式类型声明是首选。我的第一语言是 FORTRAN IV,但我学的第二语言是 QBasic,它和 C 一样要求在使用之前显式声明所有变量。

    【讨论】:

    • 这与问题无关。这不是一个答案。在为您的真实答案或问题获得一些声誉积分后,您将能够发布 cmets。但是,不要发布 cmets 作为答案。当然不要只抱怨各种语言的力量。
    猜你喜欢
    • 1970-01-01
    • 2014-10-14
    • 2013-07-11
    • 2020-08-16
    • 1970-01-01
    • 1970-01-01
    • 2020-08-03
    • 1970-01-01
    • 2022-12-17
    相关资源
    最近更新 更多