【发布时间】:2021-07-28 15:52:18
【问题描述】:
我正在使用 Knuth 算法来生成随机排列 的一个 n 元组。这是代码。固定 n,它生成随机排列并收集所有不同的排列,直到找到所有 n!排列。最后,它还会打印找到所有排列所需的试验次数。从那时起,我还插入了种子的初始化(不过,以一种非常简单和幼稚的方式)。有两个选项(A 和 B)。 A:种子在主程序中是一次性固定的。 B:每次计算随机排列时,种子都是固定的(第二个选项下方有注释)。
implicit none
integer :: n,ncomb
integer :: i,h,k,x
integer, allocatable :: list(:),collect(:,:)
logical :: found
integer :: trials
!
! A
!
integer :: z,values(1:8)
integer, dimension(:), allocatable :: seed
call date_and_time(values=values)
call random_seed(size=z)
allocate(seed(1:z))
seed(:) = values(8)
call random_seed(put=seed)
n=4
ncomb=product((/(i,i=1,n)/))
allocate(list(n))
allocate(collect(n,ncomb))
trials=0
h=0
do
trials=trials+1
list=Shuffle(n)
found=.false.
do k=1,h
x=sum(abs(list-collect(:,k)))
if ( x == 0 ) then
found=.true.
exit
end if
end do
if ( .not. found ) then
h=h+1
collect(:,h)=list
print*,h,')',collect(:,h)
end if
if ( h == ncomb ) exit
end do
write(*,*) "Trials= ",trials
contains
function Shuffle(n) result(list)
integer, allocatable :: list(:)
integer, intent(in) :: n
integer :: i, randpos, temp,h
real :: r
!
! B
!
! integer :: z,values(1:8)
! integer, dimension(:), allocatable :: seed
! call date_and_time(values=values)
! call random_seed(size=z)
! allocate(seed(1:z))
! seed(:) = values(8)
! call random_seed(put=seed)
allocate(list(n))
list = (/ (h, h=1,n) /)
do i = n, 2, -1
call random_number(r)
randpos = int(r * i) + 1
temp = list(randpos)
list(randpos) = list(i)
list(i) = temp
end do
end function Shuffle
end
您可以检查第二个选项是否不好。对于 n=4,它需要大约 100 倍的试验才能获得排列的总数,而对于 n=5,它会卡住。
我的问题是:
-
为什么多次调用 random_seed 会给出错误的结果?我正在引入什么样的系统错误?是不是相当于只调用一次随机种子,多次启动代码(每次只产生一个随机排列)?
-
如果我想启动多次代码,计算一个排列,我猜如果我初始化随机种子我有同样的问题(不管初始化的位置,因为现在我只计算一个排列)。正确的?在这种情况下,我必须做什么才能在不破坏均匀采样的情况下初始化种子?因为如果我不以随机方式初始化种子,我会获得相同的排列。我想我可以在每次启动代码时打印和读取种子,以免从相同的伪随机数开始。但是,如果我并行启动多个代码实例,这会很复杂。
更新
我已经明白回复了。总之,如果我想通过初始化种子在每次调用时生成伪随机数,我可以做的是:
A) 旧的 gfortran
在这里使用子程序 init_random_seed()
https://gcc.gnu.org/onlinedocs/gcc-5.1.0/gfortran/RANDOM_005fSEED.html
B) 最新的 gfortran 版本
调用 random_seed()
C) Fortran2018
调用 random_init(repeatable, image_distinct)
问题
在 C) 的情况下,我应该设置 repeatable=.false., image_distinct=.true. 每次都有不同的随机数?
以可移植方式编写代码的有效方法是什么? 无论编译器是什么,它都可以工作吗? (我的意思是,代码可以识别可用的内容并相应地工作)
【问题讨论】:
-
究竟是什么“为什么会这样?”?你到底关心什么?
-
现在清楚了吗?
-
只有在使用 Fortran 的
coarray功能时,random_init的image_distinct参数才重要。
标签: fortran permutation random-seed