FORTRAN:一个随机数生成器必须被调用多次?如何播种



我的随机随机数生成器必须被调用多次(未指定):

    WRITE(*,*) Random_Number_routine([optional seed])

我的随机数生成器有一个可选的整数参数,如果存在,它会将其用作种子。如果不存在,则调用system_clock(i)并使用i作为种子。到目前为止还不错。但是,如果Random_Number_routine调用过快,每秒调用一次以上,那么系统时钟就没有机会更改COUNT参数,并返回相同的值。作为一个例子,请考虑对https://gcc.gnu.org/onlinedocs/gfortran/SYSTEM_005fCLOCK.html

PROGRAM test_system_clock
    INTEGER :: count, count_rate, count_max
    DO i = 1, 100
        CALL SYSTEM_CLOCK(count, count_rate, count_max)
        CALL srand(count) 
        WRITE(*,*) count, count_rate, count_max, rand()
    END DO
END PROGRAM test_system_clock

testrongystem_clock的输出为

 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320589        1000  2147483647  0.640894175    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 5320590        1000  2147483647  0.640901804    
 4928363        1000  2147483647

count参数只接受两个值:5320589和5320590。如果此参数用作srand(即)中的种子

  Call srand(count) 

然后使用相同的种子并生成相同的随机数,这可以在数据的最后一列中看到。唯一的解决方法是从单个种子生成$N$随机变量,即

CALL SYSTEM_CLOCK(count, count_rate, count_max)
Call srand(count) 
DO j = 1, n
    res(j) = rand()
END DO

然而,这假设一个人知道在调用例程之前需要多少随机变量——在这种情况下,我不知道。

我唯一的另一条途径是使用Fortran的save属性并保存使用的上一个种子——如果这是第一次执行例程,它会使用SYSTEM_CLOCK来确定种子,那么existent会运行更新种子的某个整数。然而,这不会产生随机数,因为只使用序列中的第一个数字。

其他软件如何解决这个问题?像MATLAB这样的程序是如何做到这一点的?我如何调用随机数例程并保证一个新的随机数?

更新:在回答francescalus评论时:因此,在显示的第一块代码中,我已经调用了该例程100次,表中的最后一列给出了为每次调用生成的随机数。随机数只取两个值:0.640894175和0.640901804。这似乎是由于只有两个种子值可用(如第一列所示)。我想确定的是,考虑到我调用例程的速度比种子值的变化快,我如何获得随机数。即,如果我调用例程100次,那么我期望100个随机值,而不是相同的两个值。可能是Fortran错误吗?

每次循环时都要对RNG进行补种。我的FORTRAN非常生疏,(FORTRAN IV有人吗?)但我怀疑你需要把srand()调用从循环中拉出来。类似于:

PROGRAM test_system_clock
  INTEGER :: count, count_rate, count_max
  CALL SYSTEM_CLOCK(count, count_rate, count_max)
  CALL srand(count) 
  DO i = 1, 100
    CALL SYSTEM_CLOCK(count, count_rate, count_max)
    WRITE(*,*) count, count_rate, count_max, rand()
  END DO
END PROGRAM test_system_clock

通常,您应该在程序开始时用srand()为RNG播种一次,然后重复调用rand()以生成伪随机序列,而无需重新播种。

rand()方法是全局可用的系统调用,srand也是。在程序的初始化阶段调用srand一次(可以是在main中,也可以是从main中首先调用的例程)。然后,您可以从程序中的任何位置任意多次调用rand,以根据需要获得伪随机值,而无需事先知道需要多少。这里的关键概念是srand用于初始化PRNG的状态,并且每次运行程序时只应调用一次。

当你在做的时候,你应该考虑用一个质量更好的生成器取代rand,它很糟糕。gnu.org上的rand网页指出random_number是一个更好的选择。

最新更新