2

我尝试用现代 fortran(2018 年?)编写代码,我的目标之一是能够将像这样的子例程(旧的 fortran 77)转换为最新的 fortran(2018 年?)

    subroutine nobin(e,j,f)
         common/binin/bini(40),nbn
         er=e
         do 100 i=j,40
         er=er-bini(i)
         if(er.le.0.0) go to 200
         100 continue
         f1=er/bini(40)
         f=41.+f1-float(j)
         if(j.gt.40) f=f1
         go to 300
     200 f=float(i-j)+er/bini(i)+1.0
     300 continue
         return
         end

到目前为止,我能够写出这样的东西(见下文),但我只对标量变量成功了。当我必须使用数组时,我有点卡住了。特别是我应该分配然后给数组 Bini 一些值(旧 fortran 子例程中的公共块)。然后在类中定义的函数(find_bin_nobin)中使用这些数组。感谢任何建议以及对代码的任何正式改进。非常感谢!

   module precision
   implicit none
   public
   integer, parameter :: pr = selected_real_kind(12,300)
   integer, parameter :: ir = 4
   end module precision

   module constants
   use precision
   implicit none
   public
   real   ( kind = pr ), parameter :: zero  = 0.0_pr
   real   ( kind = pr ), parameter :: one   = 1.0_pr
   real   ( kind = pr ), parameter :: four  = 4.0_pr
   real   ( kind = pr ), parameter :: pi = four * atan(one)
   end module constants

   module class_Dntrnpr

   use precision
   use constants, only : zero, one
   implicit none
   type Find_bin
   real   ( kind = pr ) :: e
   integer( kind = ir ) :: j
   real   ( kind = pr ), allocatable, dimension(:) :: bin

    contains

   procedure :: f => find_bin_nobin
   end type Find_bin

   contains

   function find_bin_nobin(x, n) result(f)
    class(Find_bin), intent(inout) :: x
    integer( kind = ir ), intent(in) :: n
    real   ( kind = pr ) :: f, f1, er
    integer( kind = ir ) :: i, k
    allocate(x%bin(n))
    er = x%e
    i  = x%j
    k  = i
    er = er - x%bin(i)
    do while ( er <= zero )
     er = er - x%bin(i)
     i = i + 1
    enddo
    f1 = er / x%bin(n)
    f  = ( n + 1 ) + f1 - dble(k) 
    if ( k > n ) then
     f = f1; return
    else
     f = dble(i-k) + er / x%bin(i) + one
    endif
    return
    end function find_bin_nobin

   end module class_Dntrnpr

   program test

   use class_Dntrnpr
   implicit none

   integer( kind = ir ) :: nbmax,i
   real   ( kind = pr ), allocatable, dimension(:) :: bini

   type(Find_bin) :: en
   !  type(Find_bin), allocatable, dimension(:) :: bin

   en%e = 2.0
   en%j = 1
   nbmax = 40

   allocate(bini(nbmax))
   bini = 1.0

   end program test
4

1 回答 1

2

这看起来可能更适合代码审查,但我还是要投入 6 美分。如果我在下面粗鲁,请提前道歉;这不是我的意图,我只是想在我看到它们时提出建议,并避免将建议与细节混淆。

模块精度

   module precision
   implicit none
   public
   integer, parameter :: pr = selected_real_kind(12,300)
   integer, parameter :: ir = 4
   end module precision
  • 如果您使用的是自由格式的 Fortran(而且您确实应该这样做),您应该缩进以提高可读性。
  • selected_real_kind(15,307)比双精度更标准。(12,300)也许考虑改用real64from iso_fortran_env
  • selected_int_kind(9)比 更便携4

所以我会把它写成:

module precision
  implicit none
  public
  integer, parameter :: pr = selected_real_kind(15,307)
  integer, parameter :: ir = selected_int_kind(9)
end module precision

模块常量

   module constants
   use precision
   implicit none
   public
   real   ( kind = pr ), parameter :: zero  = 0.0_pr
   real   ( kind = pr ), parameter :: one   = 1.0_pr
   real   ( kind = pr ), parameter :: four  = 4.0_pr
   real   ( kind = pr ), parameter :: pi = four * atan(one)
   end module constants
  • 再次缩进。
  • 像这样的参数zero = 0.0_pr通常是不好的做法。使用现代编译器,它们不会给您任何加速,并且会降低可读性。只需使用实际数字。
  • 我更real(pr)喜欢real (kind = pr). 它传达了相同的信息,并且更简洁。

所以我会把它写成:

module constants
  use precision
  implicit none
  public
  real(pr), parameter :: pi = 4.0_pr * atan(1.0_pr)
end module constants

类定义

   module class_Dntrnpr

   use precision
   use constants, only : zero, one
   implicit none
   type Find_bin
   real   ( kind = pr ) :: e
   integer( kind = ir ) :: j
   real   ( kind = pr ), allocatable, dimension(:) :: bin

    contains

   procedure :: f => find_bin_nobin
   end type Find_bin

   contains
  • 再次缩进。
  • 如果一个模块所做的只是定义一个类,那么它应该以该类命名。
  • 使用额外的空格对齐多行是不好的做法(例如,您的and声明ej
  • 考虑重命名Find_bin为更具描述性的名称。这门课是“找垃圾箱”吗?
  • 是否bin代表单个垃圾箱,还是应该是bins
  • 为了一致性,f => find_bin_nobin真的应该是nobin => nobin_Find_bin.
  • 该函数find_bin_nobin做了两个不同的事情: intilalisebin和 calculate f。理想情况下,OOP 过程应该分为subroutine修改其参数function的 s 和不修改其参数的 s。bin在这种情况下,可以在构造函数中进行初始化。

所以我会把它写成:

module class_Find_bin
  use precision
  implicit none
  
  type Find_bin
    real(pr) :: e
    integer(ir) :: j
    real(pr), allocatable, dimension(:) :: bin
  contains
    procedure :: nobin => nobin_Find_bin
  end type Find_bin
  
  ! Constructor for type Find_bin.
  interface Find_bin
    module procedure new_Find_bin
  end interface
contains

课堂程序

   contains
   
   function find_bin_nobin(x, n) result(f)
    class(Find_bin), intent(inout) :: x
    integer( kind = ir ), intent(in) :: n
    real   ( kind = pr ) :: f, f1, er
    integer( kind = ir ) :: i, k
    allocate(x%bin(n))
    er = x%e
    i  = x%j
    k  = i
    er = er - x%bin(i)
    do while ( er <= zero )
     er = er - x%bin(i)
     i = i + 1
    enddo
    f1 = er / x%bin(n)
    f  = ( n + 1 ) + f1 - dble(k) 
    if ( k > n ) then
     f = f1; return
    else
     f = dble(i-k) + er / x%bin(i) + one
    endif
    return
    end function find_bin_nobin

   end module class_Dntrnpr
  • 再次缩进。再次对齐多行。
  • 考虑在执行不同操作的代码部分之间添加空行。
  • 如上所述,考虑find_bin_nobin分成构造函数和计算函数f
  • 你从来没有设置x%bin。您用 分配它allocate(x%bin(n)),然后开始读取它而不先设置它的值。
  • 您的循环版本i与旧版本不同。
  • 该变量k是不必要的,并且会增加混乱。
  • dble(foo)应该是real(foo, pr)
  • 避免将;两行合二为一。
  • 在旧代码中,if(j.gt.40)没有else. 该行200 f=float(i-j)+er/bini(i)+1.0总是被 line 跳过go to 300
  • 您不需要return在程序结束时。这是自动发生的。

所以我会把它写成:

contains
  function new_Find_bin(e, j, n) result(this)
    real(pr), intent(in) :: e
    integer(ir), intent(in) :: j
    integer(ir), intent(in) :: n
    type(Find_bin) :: this
    
    this%e = e
    this%j = j
    allocate(this%bin(n))
    ! Initialise bin here.
  end function
  
  function nobin_Find_bin(this) result(f)
    class(Find_bin), intent(in) :: this
    real(pr) :: f
    
    real(pr) :: f1, er
    integer(ir) :: i, n
    
    er = this%e
    n = size(this%bin)
    
    do i=this%j,n
      er = er - this%bin(i)
      if (er<=0.0_pr) then
        f = real(i-this%j, pr) + er/this%bin(i) + 1.0_pr
        return
      endif
    enddo
    
    f1 = er / this%bin(n)
    f  = ( n + 1 ) + f1 - real(this%j, pr)
    
    if ( this%j > n ) then
      f = f1
    endif
  end function find_bin_nobin
end module class_Find_bin

主程序

   program test

   use class_Dntrnpr
   implicit none

   integer( kind = ir ) :: nbmax,i
   real   ( kind = pr ), allocatable, dimension(:) :: bini

   type(Find_bin) :: en
   !  type(Find_bin), allocatable, dimension(:) :: bin

   en%e = 2.0
   en%j = 1
   nbmax = 40

   allocate(bini(nbmax))
   bini = 1.0

   end program test

如上所述更改模块后,我将其写为:

program test
  use class_Find_bin
  implicit none
  
  type(Find_bin) :: bin
  real(pr) :: f
  
  bin = Find_bin(2.0_pr, 1, 40)
  f = bin%nobin()
end program

一般性评论:

  • 您的代码不包含任何注释,并且您的变量名毫无意义。如果您的代码的未来读者(可能包括未来的您)能够阅读您的代码所做的而不是必须解决它,他们会更快乐。如果这就是它们所代表的,请考虑替换 egeerwith 。error
于 2021-09-06T09:59:53.927 回答