Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's wrong with my random number generator in Fortran 95 please?

This a randon number generator module that I use to compile along with my main program (not listed here) When I try to compile my random number generator module to see if it works, I get the following message:

at line 61: call random_seed( put = seed) Error: size of 'put' argument of 'random_seed' intrinsic too small <4/12>

What does it mean? How can I fix it?

module random_angle
 contains
 0
    integer Function random_integer (N)         ! return a random integer between 1 and N
        integer, intent(in) :: N
        real*8 :: x

        call random_number(x)
        random_integer = floor(real(N)*x)+1

    end function random_integer

    Real*8 Function gasdev()           !  ch7.pg.280:gaussian distribution function using ran1 as random # generator

        implicit none
!       integer, intent(inout) :: idum
        integer, save::iset
        real*8:: fac,rsq,v1,v2
        real*8, dimension(2) :: x
        real*8, save :: gset

!       if (idum.lt.0) iset=0
        if (iset.eq.0) then
          rsq = 0.0
          do while (rsq > 1.0.or.rsq==0)  
            call random_number(x)
            v1=2.*x(1)-1
            v2=2.*x(2)-1
            rsq=v1**2+v2**2
!    print *, v1, v2,rsq
          end do    

          fac=sqrt(-2.*log(rsq)/rsq)
          gset=v1*fac
          gasdev=v2*fac
          iset=1
        else
            gasdev=gset
            iset=0
        endif

        return

    end Function gasdev

    real*8 function NormalRandom (average, stddev)
        implicit none
        real*8, intent(in):: average, stddev
        NormalRandom = average + stddev*gasdev()

    end function NormalRandom

    subroutine setSEED (seed)
        implicit none

        real*8:: x
        integer, dimension(4), intent(inout):: seed
        if (seed(1) == 0.0) &
            seed = floor(1000*secnds(0.0)) +(/0, 37, 74, 111 /)  
        call random_seed( put=seed)

    end subroutine setSEED

end module random_angle
like image 931
Demetri Papamichalis Avatar asked Apr 02 '15 21:04

Demetri Papamichalis


People also ask

Is there a command to generate random number variables for sampling?

Generating random number variables is necessary for sampling. I search between the same code (to find efficient structure) and see they use the "RANDOM_SEED" command in it. I search on the net to find something to help me with this command and find this: RANDOM_SEED. But I gained nothing from it.

How to set a pseudo-random sequence to some random state?

So you can just call RANDOM_INIT (.false.,.true.) and the pseudo-random sequence will be set to some random-ish initial state. SET_SEED is used with a different obsolete generator, ignore it.

How to check if my compiler supports random_init?

Check the manual of your compiler version. You didn't ask for it, but if your compiler is sufficiently new, e.g. gfortran 9 or later, it might support the Fortran 2018 intrinsic subroutine RANDOM_INIT (). It has two logical arguments.


1 Answers

When the compiler says

Error: size of 'put' argument of 'random_seed' intrinsic too small <4/12>

it means that the size of your variable seed is too small.

In this case you have seed of size 4 (and I guess the compiler must be expecting (at least) 12).

The size of the array must be of a certain size which depends on the compiler. You can determine, portably, the required size by a call to random_seed with another argument

integer seed_size
integer, allocatable :: seed(:)

call random_seed(size=seed_size)
allocate(seed(seed_size))
seed = ...
call random_seed(put=seed)

As Vladimir F points out in a comment, the gfortran document itself has an example of this approach.

If you don't care about portable, you could just use an array of size 12 with your choice of values.


As more advanced reading, I'll say another thing. The example I gave above really wasn't very comparable to your code. That is, you say that the input to the seed setting subroutine is guaranteed to be at least of size 4 and it may, or may not, contain values you want to use as seed.

As I noted above, you could change that to 12, but that isn't portable. If you want to be portable things get more awkward.

integer, dimension(4), intent(inout):: seed

has as dummy argument an explicit shape array of size 4. The actual argument in the main program is an array at least that size. However, this size is a specification expression and, alas, call random_seed(size=seed_size) doesn't give us something we can use in a specification expression.

Perhaps something like

subroutine setSEED (seed)
  integer, allocatable, intent(inout) :: seed(:)
  integer seed_size

  ! Determine the correct size for the seed
  call random_seed(size=seed_size)

  ! If our seed isn't set, or is too small, kill it.
  if (ALLOCATED(seed)) then
    if (SIZE(seed)<seed_size.or.seed(LBOUND(seed,1))==0.) deallocate(seed)
  end if

  ! If seed isn't allocated (perhaps we killed it because it was too small)
  ! then allocate it to the correct size and initialize it.
  if (.not.ALLOCATED(seed)) then
    allocate(seed(seed_size))
    seed = ...  ! Our fallback seed initialization
  end if

  ! Finally, put the seed.  Using one we set, or the one originally given.
  call random_seed(put=seed)

end subroutine

This, of course, requires that the actual argument be allocatable, but if you're handling portable seed setting that's a good thing.

like image 93
francescalus Avatar answered Dec 16 '22 20:12

francescalus