DO 循环中的累加器
Accumulator within a DO loop
我的目标是创建 10,000 个随机生成的 0 和 1 之间的数字,将它们组织到 0 和 1 之间均匀分布的十个 bin 中,并计算每个 bin 的频率。到目前为止,这是我的代码。
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 块更有效的方法来解决这个问题?
在你长
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
的值的数量。
编辑
我还想进一步指出 High Performance Mark 的答案,他不是为每个值单独调用 RANDOM_NUMBER
,而是使用它来生成整个随机数数组。
此外,他利用 bin 是固定且等距的事实来直接从随机值计算 bin 编号,而不是像我的版本那样将它与每个 bin 进行比较。
这两者都使程序更快。
如果执行速度是一个人的主要关注点,并且愿意用 space 换取时间,这可能很有吸引力:
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 倍。
我的目标是创建 10,000 个随机生成的 0 和 1 之间的数字,将它们组织到 0 和 1 之间均匀分布的十个 bin 中,并计算每个 bin 的频率。到目前为止,这是我的代码。
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 块更有效的方法来解决这个问题?
在你长
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
的值的数量。
编辑
我还想进一步指出 High Performance Mark 的答案,他不是为每个值单独调用 RANDOM_NUMBER
,而是使用它来生成整个随机数数组。
此外,他利用 bin 是固定且等距的事实来直接从随机值计算 bin 编号,而不是像我的版本那样将它与每个 bin 进行比较。
这两者都使程序更快。
如果执行速度是一个人的主要关注点,并且愿意用 space 换取时间,这可能很有吸引力:
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 倍。