是否可以改进以下 Fortran 代码?

F2H*_*ell 1 optimization fortran

这里\xe2\x80\x99是使用该特定算法的已完成程序之一。

\n\n
        program Lotto\n\n        implicit none\n\n        INTEGER::MAXTHREADS\n        INTEGER::I,N,Q,RAN,RAN4(4),N129(9),LOTTO5(5)\n        REAL::R,TI,TIMELY,SEC\n\n        CALL RANDOM_SEED()\n!____________________________________________________________________________\n!____________________________________________________________________________\n\n        N=0\n        RAN4=0\n        DO\n            CALL RANDOM_NUMBER(R)\n            RAN=1+INT(9*R)\n            IF(COUNT(RAN==RAN4(1:4))/=0)CYCLE\n            N=N+1\n            RAN4(N)=RAN\n            IF(N==4)EXIT\n        ENDDO\n\n        N129=[1,2,3,4,5,6,7,8,9]\n        N129(RAN4(1:4))=0\n\n        N=0\n        DO I=1,9\n            IF(N129(I)==0)CYCLE\n            N=N+1\n            LOTTO5(N)=I\n        ENDDO    \n        PRINT*,LOTTO5\n\n        end program Lotto\n
Run Code Online (Sandbox Code Playgroud)\n\n

针对我原来的帖子,High Performance Mark 提出了两个重要的观察结果:

\n\n
    \n
  1. 如果不了解代码片段的使用上下文,就无法对它进行任何描述。和

  2. \n
  3. 无论如何,可能不值得花时间去打扰那些小事。(对措辞表示歉意。)

  4. \n
\n\n

上面的简短程序 \xe2\x80\x9cLotto\xe2\x80\x9d 仅作为一个小演示,用于在 \xe2\x80\x93 上下文中显示 \xe2\x80\x93 如何使用过滤算法。当然,作为仅几行代码的集合,它可能无法改进。然而,我本来希望并非如此。当每天处理 1500 到 2000 行新的 Fortran 代码,并且类似的代码片段在同一程序中出现 10 或 12 次时,如果您可以改进(优化)其中一个,则可以优化它们,至少可以减少一些执行时间,这间接说明了 HPM\xe2\x80\x99 的第二个观察结果。作为一名 Fortran 程序员,我只有一个目标,那就是用尽可能短的执行时间产生期望的结果。这是\xe2\x80\x99 的好说法。更现实的说法是: \xe2\x80\x9c 花费最少的钱,产生想要的结果。 \xe2\x80\x9d 由于 \xe2\x80\x9coptimization\xe2\x80\x9d 是众多标签之一, Stack Overflow 使用时,我希望能够进行一些涉及优化的讨论,但显然情况并非如此。我猜还有其他论坛。一些年轻的用户可能对代码优化的工作原理感兴趣,但他们中的许多人似乎非常专注于无法正确执行某些代码集合。

\n\n

HPM\xe2\x80\x99s 在评论帖子时总是会提出批评,所以这是我对他的最后两点歉意:

\n\n
    \n
  1. 您关于删除声明的说法是正确的。程序的 \xe2\x80\x9cpreparatory\xe2\x80\x9d 部分由 15 个可操作的 Fortran 语句、3 个注释行和 2 个 OMP 指令组成。为了清楚起见,在总共 20 行中,我应该省略其中 14 行,包括 3 条注释行和 2 条 OMP 指令。我现在已经把它们删除了。但是,我的 Microsoft Visual Studio 设置为使用 OMP 执行所有程序,并且它还按原样执行 \xe2\x80\x9cLotto\xe2\x80\x9d ,提供线程计数和其他线程信息。Lotto 在 OMP 中运行良好,但出于演示目的,我当然不需要所有 \xe2\x80\x98lettuce\xe2\x80\x99。

  2. \n
  3. 我\xe2\x80\x99对于多语句行感到抱歉。我在普通编程中不使用它。之所以在那里,是因为我一直认为 Stock Overflow 希望他​​们打印的程序尽可能简短。难道我错了吗?我已经去掉了多层衬里。

  4. \n
\n

Hig*_*ark 5

好吧,我已经上钩了……

如果我正确理解代码(如果我不理解,那么你可以忽略整个答案),它会选择(在示例中)数组的随机 5 个元素(两次没有元素)[1,2,3,4,5,6,7,8,9]

经过一番挠头之后,我将这个问题转化为对数组进行随机排列并选择前 5 个元素的问题。这是我编写的一个小函数,用于使用 Knuth 的洗牌进行随机排列

  FUNCTION random_perm(n) RESULT(perm)
    ! return a random permutation of the integers 1..n, uses Knuth's shuffle
    INTEGER, INTENT(in) :: n
    INTEGER, DIMENSION(n) :: perm
    INTEGER, DIMENSION(n) :: randi
    REAL, DIMENSION(n) :: randr
    INTEGER :: tmp, ix, jx

    CALL random_SEED()
    CALL random_NUMBER(randr)
    randi = 1+INT(n*randr)
    perm = [(ix,ix=1,n)]

    DO ix = 1, n-1
       jx = randi(ix)
       tmp = perm(ix)
       perm(ix) = perm(jx)
       perm(jx) = tmp
    END DO  

  END FUNCTION random_perm
Run Code Online (Sandbox Code Playgroud)

OP 可以使用这样的函数:

n129 = random_perm(9)
lotto5 = n129(1:5)
Run Code Online (Sandbox Code Playgroud)

此时lotto5尚未排序。如果这是重要的一种“排序”方法,结果将是将前两行替换为

 n129 = random_perm(9)
 ix = 1
 DO jx = 1, 9
       IF (ANY(n129(1:5)==jx)) THEN
          lotto5(ix) = jx
          ix = ix+1
       END IF
 END DO
Run Code Online (Sandbox Code Playgroud)

从有限的测试来看:

  • 我相当有信心这能正常工作。
  • 它比 OP 的代码慢大约 2-4%。

如果 OP 唯一关心的是速度,OP 可能会关心手动“内联”该函数,看看它是否会产生一点差异。我没有这样做过,也不会这样做。我认为在独立函数中拥有随机排列生成器很有用。OP 暗示这个函数(或者更确切地说,OP 在发布的代码中表示它)是更大代码的一部分,因此我不知道我提供的函数在该上下文中是否有用。

最后,为了解决OP更广泛的问题,我写的比原来的更好吗?

不,它更慢。

可以说,是的。如果 OP 的目的是获取m整数随机排列的第一个元素1,2,...,n,那么返回随机排列的函数对于大型程序来说是一个有用的组件。但是 OP 可能会合理地认为他的(?)代码是该函数的更好(因为更快)的实现,但只是包装方式不同。

这让我们回到了起点,“更好”是什么意思?