标量到数组的内在赋值

2023-12-04

来自 Fortran 2008 规范,7.2.1.3.5

如果 expr 是标量并且变量是数组,则 expr 被视为与形状相同的数组 数组中每个元素都等于 expr 标量值的变量。

我见过以下编码风格:

A:

integer, dimension(3) :: x
do i=1,3
  x(i) = 1
enddo

B:

integer, dimension(3) :: x
x(:) = 1

C:

integer, dimension(3) :: x
x = 1

将标量值分配给数组(性能和可读性)的最佳实践是什么?

Note: A闻起来像 Fortran77,我有一种感觉C可能会让未来的读者感到困惑吗?


简短回答:

根据我的经验,情况 (A) 始终优于 Fortran 数组语法。然后,情况 (C) 优于情况 (B),仅在特殊情况下编译器必须做一些额外的工作来理解 (:) 的含义,否则这两种表示法通常是相同的。但是,到目前为止,最好的选择似乎是 DO CONCURRENT,IFF 编译器支持它,例如 Intel Fortran 编译器 2015,并且我已经看到 DO CONCURRENT,IFF 编译器优化标志打开时的性能提升。请注意其他 Fortran 编译器中的 DO CONCURRENT 状态,因为它们可能不会对其进行优化,而只是将 DO CONCURRENT 转换为 DO 循环,在这种情况下可能会发生性能损失,具体取决于标头的编写方式(下面的长答案)。

长答案:

今天早上,我根据自己的知识,使用以下代码比较了 DO 循环、数组分配和 DO CONCURRENT:

program performance_test
implicit none
integer :: i,j,k, nloop = 10**4
integer, dimension(:,:), allocatable :: variable
real*8  :: tstart,tend
allocate(variable(nloop,nloop))

call cpu_time(tstart)
do k = 1,10
  variable = 0.0
end do
call cpu_time(tend)
write(*,*) tend-tstart

call cpu_time(tstart)
do k = 1,10
  do j = 1,nloop
    do i = 1,nloop
      variable(i,j) = 0.0
    end do
  end do
end do
call cpu_time(tend)
write(*,*) tend-tstart

call cpu_time(tstart)
do k = 1,10
  do concurrent (j = 1:nloop, i = 1:nloop)
    variable(i,j) = 0.0
  end do
end do
call cpu_time(tend)
write(*,*) tend-tstart

call cpu_time(tstart)
do k = 1,10
  do i = 1,nloop
    do j = 1,nloop
      variable(i,j) = 0.0
    end do
  end do
end do
call cpu_time(tend)
write(*,*) tend-tstart

call cpu_time(tstart)
do k = 1,10
  do concurrent (i = 1:nloop, j = 1:nloop)
    variable(i,j) = 0.0
  end do
end do
call cpu_time(tend)
write(*,*) tend-tstart    

end program performance_test

编译器是Intel Fortran 2015。

Result:

无论编译器优化标志是打开还是关闭,DO CONCURRENT 和简单的 DO 循环都优于 Fortran 数组语法(至少在这个示例中,据我所知),但仅当它是在考虑 Fortran 列顺序的情况下完成的。从技术上讲,我不认为人们可以用 DO CONCURRENT 来谈论按列或按行,就像我在下面使用的那样。由于没有优化标志,DO CONCURRENT 基本上是简单的 DO 循环。通过优化标志,编译器本身将处理循环的顺序。

到目前为止,我在英特尔 Fortran 编译器 2015 中使用 DO CONCURRENT 的经验:在复杂的 DO 循环中,编译器无法轻松解读并发性,与简单的 DO 循环相比,它会带来一些性能提升,并且在其他情况下,它与 DO 循环一样好,应该如此,除非它与 OPENMP 指令结合使用,这会导致今天的灾难,至少就我的实验而言是这样。

没有编译器优化:

array syntax               :  4.44602850000000
do-loop, column-wise       :  3.82202450000000
do concurrent, column-wise :  3.91562510000000
do-loop, row-wise          :  19.1413227000000
do concurrent, row-wise    :  19.2817236000000

O2 水平优化:

array syntax               :  0.218401400000000
do-loop, column-wise       :  0.187201200000000
do concurrent, column-wise :  0.171601100000000
do-loop, row-wise          :  0.187201200000000
do concurrent, row-wise    :  0.171601100000000
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

标量到数组的内在赋值 的相关文章

  • Fortran 小数和千位分隔符

    有没有办法更改逗号的句点小数分隔符 另外 如何使输出数字具有千位分隔符 这可以是逗号 句号 空格 打开文件时使用参数 DECIMAL COMMA open 100 file logfile status unknown DECIMAL CO
  • Intel Fortran 错误 #6633:实际参数的类型与虚拟参数的类型不同

    对于可能在这里提出这样一个基本问题 我深表歉意 我是使用英特尔 Fortran 编程的新手 所以我认为在这种情况下 我不知道有一些东西丢失或组织错误 如果有人能在这方面帮助我 我将不胜感激 问题是我在编译代码时看到以下错误 而我相信我已经声
  • 从接口访问参数 (Fortran)

    我正在使用参数来修复所用类型的精度 在我尝试在接口中使用相同类型之前 这种方法工作得很好 考虑这个小例子 module Hello implicit none save integer parameter K selected real k
  • 如何在 makefile 中定义变量,然后在 Fortran 代码中使用它

    我试图在 makefile 中定义一个变量 然后根据是否设置了该变量 更改在我的 Fortran 例程中编译的代码块 简单的例子我无法工作 program test implicit none integer a ifdef MYVAR a
  • fortran 77 到 fortran 90 的转换器软件 [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我有 fortran 77 编码 但我想转换为 fortran 90 在哪里可以下载转换器软件 这是我帮
  • 如何为 Fortran 95+ 模块库提供显式接口,并隐藏实现

    我正在使用 gfortran 的 95 扩展 我有一个实用程序模块库 我想链接到其他项目 即作为库或共享对象 dll 但是 在 Fortran 中 我不明白如何在不维护模块接口的两个副本的情况下将接口与 Fortran 中的实现分离 在 C
  • 提高由整数商定义的变量的精度

    假设我有以下程序 program derp implicit none integer parameter ikind selected real kind 18 real kind ikind a 2 0 3 0 print a end
  • 使用命令行查找数据文件的行数

    有一种常规方法 逐行读取并检查iostat每次读数时都会达到非零或负值 不过 我想打电话system command 例行公事和 使用wc l命令来计算数量 然后想要分配要放置数据的数组的维度 例如 我以两种方式打印行数 Program T
  • Dependency Walker 未显示所有依赖的 Dll

    我有一个 fortran dll 我想知道它所依赖的程序集再分配目的 http software intel com en us forums showthread php t 73161 我发现的一件事是依赖项步行器没有显示所有依赖项 即
  • fortran中双引号和单引号的区别?

    我刚刚开始使用 Fortran 对双引号和单引号的使用感到困惑 它们是等价的 它们的用法没有区别 您可以使用它来打印引号字符之一 print print 首先打印 进而 注意 您还可以在一行中使用两个引号字符来打印一个 print prin
  • 如何包装 fortran write 语句

    我想包装 fortran写语句 http software intel com sites products documentation doclib stdxe 2013 composerxe compiler fortran lin 在
  • 纯 Fortran 过程中的 I/O

    我正在尝试将错误检查合并到我正在编写的纯过程中 我想要这样的东西 pure real function func1 output unit a implicit none integer a output unit if a lt 0 th
  • 指定 gfortran 应该在其中查找模块的目录

    我目前基于模块来编译程序 例如主程序foo这取决于模块bar 如下 gfortran c bar f90 gfortran o foo exe foo f90 bar o 当foo f90 and bar f90位于同一目录中 如何指定 g
  • 在一条语句中对多个变量进行相同的赋值

    有没有一种方法可以为不同的变量分配相同的值 而无需在单个语句中构造数组 例如 如果我有变量a b c d and e 我可以分配类似的东西吗 a b c d e 10 0 我知道我可以用一行来做 a 10 0 b 10 0 c 10 0 d
  • 如何在Fortran代码中将二维数组转换为一维数组?

    如何将 r i j 转换为一维数组以便可以轻松地对数字进行排序 program sort implicit none character CN 8 O 7 integer j iconf nconf integer i nbins t in
  • 识别操作系统

    我在 Intel 编译器上的 Fortran 90 代码取决于它运行的操作系统 例如 if OS win7 then do X else if OS linux then do y end if 我如何以编程方式执行此操作 您可以使用预处理
  • gfortran 支持尾调用消除吗?

    我编写了这个小程序来测试 gfortran 是否执行尾调用消除 program tailrec implicit none print tailrecsum 5 0 contains recursive function tailrecsu
  • 如何在 makefile 中拥有正确的 .mod 顺序

    我正在尝试用 Fortran 为我的项目创建一个 Makefile 并使其可在现在的项目中重用 我经过多次尝试后得出的 Mkefile 如下 问题是它在少数情况下工作正常 但现在我有这个文件 main f90 初始 f90 参数 f90 函
  • Fortran 意图(inout)与省略意图

    良好的实践表明 Fortran 中的子例程参数每个都应具有指定的意图 即intent in intent out or intent inout 如上所述这个问题 https stackoverflow com questions 1011
  • 带有过程参数的通用类型绑定过程

    我正在尝试编写一个通用的类型绑定过程 它将不同的回调函数作为参数 当编译以下代码 使用 ifort 12 1 3 时 我收到以下警告 module test type a type contains procedure t s gt at

随机推荐