当前位置: 首页 > 知识库问答 >
问题:

m维上n维数组求和的最紧凑方法

孔志强
2023-03-14
PROGRAM sum_test

  IMPLICIT NONE

  INTEGER :: a(2,2,2) = reshape( (/1, 2, 3, 4, 5, 6, 7, 8/), (/2,2,2/), order = (/ 1, 2, 3 /) )
  INTEGER :: b(2,2)
  INTEGER :: c(2)
  INTEGER :: d(2)

  d = SUM(SUM(a, DIM=3), DIM=2)

  WRITE (*,*) d

END PROGRAM sum_test

这给出了预期的结果。然而,如果我有更多的维度,这可能会变得很难读懂。那么有没有“更好”的方法来实现这一点呢?例如,在Pythonnumpy中,可以将一系列整数传递给sum命令。

编辑:

为了测试@Francescalus建议的不同解决方案的性能,我编写了一个小程序,并在我的笔记本电脑上用两个不同的编译器编译(带有高塞拉的mac,编译器是G95GFORTRAN-MP-7)和我现有的两台linux机器上编译。对于每个编译器,我都使用-o2作为优化选项。

PROGRAM sum_performance
  IMPLICIT NONE

  INTEGER, PARAMETER :: size = 100
  REAL :: array(size, size, size, size)
  REAL, DIMENSION(size, size) :: res11, res12, res13, res14
  REAL, DIMENSION(size, size) :: res21, res22, res23, res24

  INTEGER :: i,j,k,l
  INTEGER :: clock_start, clock_stop, clock_rate
  INTEGER :: count
  INTEGER, PARAMETER :: repeat = 100

  !getting clock rate:
  CALL SYSTEM_CLOCK(count_rate = clock_rate)

  !setting up array:
  CALL RANDOM_NUMBER(array)

  !summing second and fourth index
  WRITE (*,*) 'second and fourth rank'

  CALL SYSTEM_CLOCK(count = clock_start)
  DO count = 1,repeat
     res11 = SUM(SUM(array, DIM = 4), DIM = 2)
  END DO
  CALL SYSTEM_CLOCK(count = clock_stop)
  WRITE(*,*) 'chained sum:  ', (REAL(clock_stop - clock_start)/&
       REAL(clock_rate))/REAL(repeat)

  CALL SYSTEM_CLOCK(count = clock_start)
  DO count = 1,repeat
     DO l = 1,size
        DO j = 1,size
           res12(j,l) = SUM(array(:,j,:,l))
        END DO
     END DO
  END DO
  CALL SYSTEM_CLOCK(count = clock_stop)
  WRITE(*,*) 'nested do:    ', (REAL(clock_stop - clock_start)/&
       REAL(clock_rate))/REAL(repeat)

  CALL SYSTEM_CLOCK(count = clock_start)
  DO count = 1,repeat
     FORALL (j = 1:size, l = 1:size)
           res13(j,l) = SUM(array(:,j,:,l))
     END FORALL
  END DO
  CALL SYSTEM_CLOCK(count = clock_stop)
  WRITE(*,*) 'forall:       ', (REAL(clock_stop - clock_start)/&
       REAL(clock_rate))/REAL(repeat)


 !summing second and fourth index
  WRITE (*,*)
  WRITE (*,*) 'third and fourth rank'

  CALL SYSTEM_CLOCK(count = clock_start)
  DO count = 1,repeat
     res21 = SUM(SUM(array, DIM = 4), DIM = 3)
  END DO
  CALL SYSTEM_CLOCK(count = clock_stop)
  WRITE(*,*) 'chained sum:  ', (REAL(clock_stop - clock_start)/&
       REAL(clock_rate))/REAL(repeat)

  CALL SYSTEM_CLOCK(count = clock_start)
  DO count = 1,repeat
     DO l = 1,size
        DO k = 1,size
           res22(k,l) = SUM(array(:,:,k,l))
        END DO
     END DO
  END DO
  CALL SYSTEM_CLOCK(count = clock_stop)
  WRITE(*,*) 'nested do:    ', (REAL(clock_stop - clock_start)/&
       REAL(clock_rate))/REAL(repeat)

  CALL SYSTEM_CLOCK(count = clock_start)
  DO count = 1,repeat
     FORALL (k = 1:size, l = 1:size)
           res23(k,l) = SUM(array(:,:,k,l))
     END FORALL
  END DO
  CALL SYSTEM_CLOCK(count = clock_stop)
  WRITE(*,*) 'forall:       ', (REAL(clock_stop - clock_start)/&
       REAL(clock_rate))/REAL(repeat)

END PROGRAM
second and fourth rank
chained sum:   0.193214
nested do:     0.140472
forall:        0.18884899

third and fourth rank
chained sum:   0.196938
nested do:     0.114286005
forall:        0.115414

对于mac gfortran-mp-7,我得到了

second and fourth rank
chained sum:    0.279830009    
nested do:      0.131999999    
forall:         0.130150005    

third and fourth rank
chained sum:     3.01672006    
nested do:      0.111460000    
forall:         0.110610001    

对于两台linux机器,相对性能与mac g95的结果相似,尽管绝对性能不同。可以看到,链接的sum解决方案显示了最差的性能(可能会因为临时创建数组而造成时间损失?)。此外,当对等级3和4求和时会发生一些有趣的事情(这是一个健壮的特性,我检查了几次)。我猜这与临时数组的创建方式有关(如果它们是创建的)。有趣的是,这只发生在两个编译器中的一个。嵌套的do循环和forall循环似乎非常相似,所以我想选择哪一个取决于个人口味。

共有1个答案

郎同化
2023-03-14

我不会低估循环结构在这种情况下的可读性。

很难明智地给出一个大致的食谱,所以我只举几个例子。

对于问题的例子:

do i=1,SIZE(d)
  d(i) = SUM(a(i,:,:))
end do
forall (i=1:SIZE(d,1), j=1:SIZE(d,2))
  d(i,j) = SUM(a(i,:,:,j)
end
do concurrent (i=1:SIZE(d,1), j=1:SIZE(d,2))
  d(i,j) = SUM(a(i,:,:,j)
end
d = SUM(RESHAPE(a,[2,4]),dim=2)
 类似资料:
  • 问题内容: 我需要有一个n维字段,其中n基于构造函数的输入。但是我什至不确定这是否可行。是吗? 问题答案: 快速的解决方案:你可以用非通用近似它的的…要深,因为你需要。但是,使用快速可能会很尴尬。 另一种需要更多工作的选择可能是使用基础平面数组表示形式来实现您自己的类型,在其中您内部计算索引,并为访问器方法提供vararg参数。我不确定它是否完全可行,但可能值得一试… 粗略的示例(未经测试,没有溢

  • 本文向大家介绍Python numpy实现二维数组和一维数组拼接的方法,包括了Python numpy实现二维数组和一维数组拼接的方法的使用技巧和注意事项,需要的朋友参考一下 撰写时间:2017.5.23 一维数组 1.numpy初始化一维数组 输出的值应该为(3,) 二维数组 2.numpy初始化二维数组 注意(3,)和(3,1)的数组是不一样的,前者是一维数组,后者是二维数组。 拼接 3.nu

  • 我有一个疑问。有没有一种有效的方法来求一个numpy矩阵的所有邻域的和而不使用几个条件? 这是一个例子: 当我运行时,它返回我3,而不是一个错误,因此如果我想将1添加到一个值的所有邻居中,我需要使用很多条件,因为我不能只使用,因为在这种情况下以及在其他情况下,它只返回我一个“假邻居”

  • 本文向大家介绍PHP 二维数组和三维数组的过滤,包括了PHP 二维数组和三维数组的过滤的使用技巧和注意事项,需要的朋友参考一下 废话不多说了,直接给大家贴代码了,具体代码如下所示: 下面一段代码给大家介绍php三维数组变二维数组 关于PHP 二维数组和三维数组的过滤小编就给大家介绍这么多,希望对大家有所帮助!

  • 本文向大家介绍js一维数组、多维数组和对象的混合使用方法,包括了js一维数组、多维数组和对象的混合使用方法的使用技巧和注意事项,需要的朋友参考一下 这篇文章的主要目的是讲解JavaScript数组和对象的混合使用,由于JS的弱检查特性,因此在JS数组中可以同时存储不同类型的变量,比如你可以把数字、字符串、字符、对象等内容放在同一个数组中。对象也可以做同样的事情,区别是对象可以指定对象里每一个成员的

  • 本文向大家介绍Python 实现取多维数组第n维的前几位,包括了Python 实现取多维数组第n维的前几位的使用技巧和注意事项,需要的朋友参考一下 现在我们有一个shape为(7352, 9, 128, 1)的numpy数组。 想要取出第2维的前三个数据,构成新数组(7352, 3, 128, 1) 我的思想是:将第2维数据转置(transpose)到第一维,再用切片(slice)取出前三个数据,

  • 本文向大家介绍详解C++中的一维数组和二维数组,包括了详解C++中的一维数组和二维数组的使用技巧和注意事项,需要的朋友参考一下 C++一维数组 定义一维数组 定义一维数组的一般格式为:     类型标识符  数组名[常量表达式]; 例如: 它表示数组名为a,此数组为整型,有10个元素。 关于一维数组的几点说明: 1) 数组名定名规则和变量名相同,遵循标识符定名规则。 2) 用方括号括起来的常量表达

  • 定义为一维数组,定义为二维数组,但这一行为是两个夜晚。原因是什么? 以及该代码的输出: