DO循环内的累加器

时间:2017-11-14 00:51:28

标签: fortran fortran90 accumulator

我的目标是在0和1之间创建10,000个随机生成的数字,将它们组织成10个均匀分布在0和1之间的区间,并计算每个区间的频率。到目前为止,这是我的代码。

program listrand
implicit none
integer :: n,p
integer :: a,b,c,d,e,f,g,h,i,j = 0
real :: xran
!real, dimension(10,2) :: bin_and_freq -- list of bins and frequency

do n = 1,10000
    call random_number(xran)
            if (xran <  0.1) then
                a = a + 1
            elseif (xran>0.1 .and. xran<0.2) then
                b = b + 1
            elseif (xran>0.2 .and. xran<0.3) then
                c = c+1
            elseif (xran>0.3 .and. xran<0.4) then
                d = d+1
            elseif (xran>0.4 .and. xran<0.5) then
                e = e + 1
            elseif (xran>0.5 .and. xran<0.6) then
                f = f+1
            elseif (xran>0.6 .and. xran<0.7) then
                g = g+1
            elseif (xran>0.7 .and. xran<0.8) then
                h=h+1
            elseif (xran>0.8 .and. xran<0.9) then
                i=i+1
            else
                j = j+1
            endif
enddo
print *, a,b,c,d,e,f,g,h,i,j
end program listrand

我收到了意想不到的输出:     988 1036 133225987 1004 934 986 1040 33770 1406729616 1052.

为什么c,h和i如此之大?另外,有没有比使用我有笨重的IF / ELSEIF块更有效的方法?

2 个答案:

答案 0 :(得分:4)

在你的长期

integer :: a,b,c,d,e,f,g,h,i,j = 0

您只是将j初始化为0,其他所有人都有随机数。如果你添加

a = 0
b = 0
c = 0
d = 0
e = 0
f = 0
g = 0
h = 0
i = 0
j = 0
在你的循环之前,一切运作良好。

至于如何简化它:

这是我的程序版本:

program listrand
implicit none
integer, parameter :: nbins = 10
integer :: n, bin
integer :: bin_hits(nbins)   ! Number of bin hits
real :: xran
real :: bin_lower(nbins)     ! Lower edge of bins
                             ! bin_lower(1) == 0.0

bin_hits = 0

! Set up equidistant bins
bin_lower = [ (real(n-1) / nbins, n = 1, size(bin_lower)) ]

do n = 1,10000
    call random_number(xran)
    bin = count(bin_lower <= xran) 
    bin_hits(bin) = bin_hits(bin)+1
enddo
do n = 1, nbins-1
    print '(2(F6.2), I6)' bin_lower(n), bin_lower(n+1), bin_hits(n)
end do
print '(2(F6.2), I6)' bin_lower(nbins), 1.0, bin_hits(nbins)
end program listrand

对于要递增bin_hits个元素的索引,我计算bin_lower中实际低于xran的值的数量。

修改

我还想进一步向下指出高性能标记的答案,而不是为每个值调用RANDOM_NUMBER单独使用它来生成整个随机数组。

此外,他还使用了这样一个事实:垃圾箱是固定的并且等距离直接从随机值计算垃圾箱数量,而不是像我的版本那样将它与每个垃圾箱进行比较。

这两个都使程序更快。

答案 1 :(得分:4)

如果执行速度是主要关注点,并且如果一个人愿意随时间交换空间,这可能会有吸引力:

PROGRAM listrand

  IMPLICIT NONE

  INTEGER, PARAMETER :: nbins = 10
  INTEGER, PARAMETER :: nsamples = 10**4
  INTEGER :: bin_hits(0:nbins-1)
  REAL :: xran(nsamples)
  INTEGER :: binned_rn(nsamples), n

  bin_hits = 0

  CALL RANDOM_NUMBER(xran)
  binned_rn = INT(nbins*xran)
  DO n = 1, nsamples
    bin_hits(binned_rn(n)) = bin_hits(binned_rn(n)) +1
  END DO

  WRITE(*,*) bin_hits

END PROGRAM listrand

在有限数量的测试中,这个版本的速度是@ chw21版本的3到4倍。