【问题标题】:Test internal representation of the type (kind)测试类型(种类)的内部表示
【发布时间】:2013-12-17 15:02:51
【问题描述】:

当测试具有不同内部表示(种类)的计算机性能时,代码或多或少保持相同,除了测试参数的定义(种类=1;种类=2)。我尝试构建不同的模块。

    module var_1
    implicit none
    real(8), allocatable :: x(:,:),xi(:,:),xt(:,:)
    integer(kind=1), allocatable :: z(:,:)
    end module var_1

    module var_2
    implicit none
    real(8), allocatable :: x(:,:),xi(:,:),xt(:,:)
    integer(kind=2), allocatable :: z(:,:)
    end module var_2

还有一个全局模块,定义了不改变的参数:

    module global
    integer :: i,j,n,p,nProcessors,s,v,w,infodpotrf,infodpotri,mkl_get_max_threads
    integer, dimension(3) :: ni = [100, 1000, 10000], pi = [100, 1000, 10000]
    integer, dimension(5) :: nProcessorsi = [1, 2, 4, 6, 12]
    real(8):: u,myone= 1.d0,t11,t22
    real:: t2,t1
    include 'omp_lib.h'
    end module global

比在程序部分我们调用稍后定义的子程序:

   program test
   call matrix_multi_inv_1
   call matrix_multi_inv_2
   end program test

子程序:

    subroutine matrix_multi_inv_1
    use global 
    use var_1

    open (unit=100,file="results.txt",status="unknown")

    do s=1,5
      nProcessors = nProcessorsi(s)
      CALL OMP_SET_NUM_THREADS(nProcessors)
      do v=1,3
        n=ni(v)
        do w=1,3
          p=pi(w)
          allocate(x(n,n),z(n,p),xi(n,n),xt(n,n))
            do i=1,n
               do j=1,p
                  call random_number(u)
                  z(i,j)=real(floor(u*3),8)
               enddo
            enddo

       1000 format(3(a20),2(i10),2(f15.3),i10)

            t11=omp_get_wtime()
            call cpu_time(t1)
            x=matmul(z,transpose(z))
            t22=omp_get_wtime()
            call cpu_time(t2)

            write(100,1000) 'x_integer_kind_1', 'G_real_8', 'matmul', n, p, t22-t11,t2-t1, mkl_get_max_threads() 

          deallocate(x,z,xi,xt)
        enddo
      enddo
    enddo
    end subroutine matrix_multi_inv_1

    subroutine matrix_multi_inv_2
    use global 
    use var_1

    open (unit=100,file="results.txt",status="unknown")

    do s=1,5
      nProcessors = nProcessorsi(s)
      CALL OMP_SET_NUM_THREADS(nProcessors)
      do v=1,3
        n=ni(v)
        do w=1,3
          p=pi(w)
          allocate(x(n,n),z(n,p),xi(n,n),xt(n,n))
            do i=1,n
               do j=1,p
                  call random_number(u)
                  z(i,j)=real(floor(u*3),8)
               enddo
            enddo

       1000 format(3(a20),2(i10),2(f15.3),i10)

            t11=omp_get_wtime()
            call cpu_time(t1)
            x=matmul(z,transpose(z))
            t22=omp_get_wtime()
            call cpu_time(t2)

            write(100,1000) 'x_integer_kind_2', 'G_real_8', 'matmul', n, p, t22-t11,t2-t1, mkl_get_max_threads() 

          deallocate(x,z,xi,xt)
        enddo
      enddo
    enddo
    end subroutine matrix_multi_inv_2

问题来了。除了调用模块部分之外,子程序完全相同。我尝试在子例程中使用包含语句,但如果调用内部子例程,这将不起作用。我也尝试使用带有属性的子程序,但我的编译器报告错误:

种类类型参数必须是编译时常量。

有谁知道如何优化代码的好解决方案。当测试 10 种不同内部表示的不同变体时,这段代码就变得太大了。

【问题讨论】:

    标签: fortran


    【解决方案1】:

    类似的问题通常通过使用 include` 的穷人模板来解决。您将公共部分移动到另一个文件,然后就可以了

    subroutine matrix_multi_inv_1
        use var_1
        include "common.f90"
    end subroutine
    
    subroutine matrix_multi_inv_2
        use var_2
        include "common.f90"
    end subroutine
    

    C 预处理器可以发挥更大的作用。

    【讨论】:

      【解决方案2】:

      为什么不将相关代码导出到文件print_huge.inc.F90 中以包含在模块中:

      ! No module ... required
      interface print_huge
        module procedure print_huge
      end interface
      
      contains
      
      subroutine print_huge(a)
        real(kind=mykind),intent(in) :: a
      
        print *, huge(a)
      end subroutine
      
      ! no end module
      

      然后你可以include这个进入不同的模块print_huge_N

      module print_huge_4
        integer,parameter :: mykind = 4
      
        include 'print_huge.inc.F90'
      end module
      
      module print_huge_8
        integer,parameter :: mykind = 8
      
        include 'print_huge.inc.F90'
      end module
      
      module print_huge_16
        integer,parameter :: mykind = 16
      
        include 'print_huge.inc.F90'
      end module
      

      注意,每个模块都有自己的mykind 定义!

      为方便起见,您可以使用定义的接口将模块捆绑到一个“超级模块”中(受 Arjen Markus 书中示例的启发):

      module print_huge_all
        use print_huge_4
        use print_huge_8
        use print_huge_16
      end module
      

      那么您的主应用程序将如下所示:

      program huge_program
        use print_huge_all
        real(kind=4)  :: a1
        real(kind=8)  :: a2
        real(kind=16) :: a3
      
        call print_huge(a1)
        call print_huge(a2)
        call print_huge(a3)
      end program
      

      输出如下:

      ./a.out 
         3.40282347E+38
         1.7976931348623157E+308
         1.18973149535723176508575932662800702E+4932
      

      子程序驻留在包含文件中,不需要调整到所有kinds。当然,您可以直接访问所有模块和/或使用=> 运算符“重命名”子例程。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-07-10
        • 2021-04-20
        • 1970-01-01
        • 2012-04-25
        • 2015-06-27
        • 2018-11-11
        • 2015-09-11
        • 1970-01-01
        相关资源
        最近更新 更多