最近,我正在研究访问fortran数组的复杂性。多亏了这些评论,这里我提供了完整的示例。
program main
implicit none
integer, parameter :: mp = SELECTED_REAL_KIND(15,307)
integer, parameter :: Np=10, rep=100
integer*8, parameter :: Ng(7) = (/1E3,1E4,1E5,1E6,1E7,1E8,1E9/)
real(mp), allocatable :: x(:)
real(mp) :: time1, time2
integer*8 :: i,j,k, Ngj
real(mp) :: temp
integer :: g
! print to screen
print *, 'calling program main'
do j=1,SIZE(Ng) !test with different Ng
!initialization with each Ng. Don't count for complexity.
Ngj = Ng(j)
if(ALLOCATED(x)) DEALLOCATE(x)
ALLOCATE(x(Ngj))
x = 0.0_mp
!!===This is the part I want to check the complexity===!!
call CPU_TIME(time1)
do k=1,rep
do i=1,Np
call RANDOM_NUMBER(temp)
g = floor( Ngj*temp ) + 1
x( g ) = x( g ) + 1.0_mp
end do
end do
call CPU_TIME(time2)
print *, 'Ng: ',Ngj,(time2-time1)/rep, '(sec)'
end do
! print to screen
print *, 'program main...done.'
contains
end program
我在一开始就认为它的复杂度是O(Np)。但这是Np = 10的时间测量:
calling program main
Ng: 1000 7.9000000000000080E-007 (sec)
Ng: 10000 4.6000000000000036E-007 (sec)
Ng: 100000 3.0999999999999777E-007 (sec)
Ng: 1000000 4.8000000000001171E-007 (sec)
Ng: 10000000 7.3999999999997682E-007 (sec)
Ng: 100000000 2.1479999999999832E-005 (sec)
Ng: 1000000000 4.5719999999995761E-005 (sec)
program main...done.
此Ng依赖性非常慢,仅在非常大的Ng时才会出现,但在增加Np时并不占主导;增加Np只会在该时间比例上乘以一个常数因子。 同样,当我使用更复杂的子例程而不是随机数时,缩放斜率似乎也会增加。 验证了计算温度和g与Ng无关。 这种情况有两个问题:
答案 0 :(得分:0)
- 我如何理解这种复杂性?我错过了多少钱 占?我猜想访问元素的成本 数组确实取决于数组的大小。一些堆栈溢出 帖子说,对于某些语言,数组访问仅花费O(1)。一世 认为它也应该适合fortran,但是我不知道为什么 并非如此。
除了您或多或少明确地向程序询问(执行循环,获取随机数等)外,还会发生许多事件,例如运行时环境的加载和输入/输出处理。为了做出有用的计时,您必须完全隔离代码与时间之间的关系,或者安排实际的计算要比其余代码花费更多的时间。
- 有什么办法可以避免这笔费用?
这是回复1:-)
现在,为解决方案:我完成了您的示例,并使其运行了数亿次迭代。见下文:
>>> from http.client import responses
>>> responses[404]
'Not Found'
我使用program time_random
integer, parameter :: rk = selected_real_kind(15)
integer, parameter :: Ng = 100
real(kind=rk), dimension(Ng) :: x = 0
real(kind=rk) :: temp
integer :: g, Np
write(*,*) 'Enter number of loops'
read(*,*) Np
do i=1,Np
call RANDOM_NUMBER(temp)
g = floor( Ng*temp ) + 1
x(g) = x(g) + 1
end do
write(*,*) x
end program time_random
对其进行了编译,并使用了bash中的gfortran -O3 -Wall -o time_random time_random.f90
函数对其进行了计时。请注意,这是非常粗糙的(并解释了为什么使迭代次数如此之大)。设置也非常简单:
time
您现在可以收集时序并观察线性复杂度。我的计算机每次迭代报告14 ns。
备注:
for ii in 100000000 200000000 300000000 400000000 500000000 600000000
do
time echo $ii | ./time_random 1>out
done
来指定真正的种类。selected_real_kind
,以确保循环没有被优化。