xref: /netbsd-src/external/gpl3/gcc/dist/libgfortran/intrinsics/random_init.f90 (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1*b1e83836Smrg! Copyright (C) 2018-2022 Free Software Foundation, Inc.
2181254a7Smrg! Contributed by Steven G. Kargl <kargl@gcc.gnu.org>
3181254a7Smrg!
4181254a7Smrg! This file is part of the GNU Fortran runtime library (libgfortran).
5181254a7Smrg!
6181254a7Smrg! Libgfortran is free software; you can redistribute it and/or
7181254a7Smrg! modify it under the terms of the GNU General Public
8181254a7Smrg! License as published by the Free Software Foundation; either
9181254a7Smrg! version 3 of the License, or (at your option) any later version.
10181254a7Smrg!
11181254a7Smrg! Libgfortran is distributed in the hope that it will be useful,
12181254a7Smrg! but WITHOUT ANY WARRANTY; without even the implied warranty of
13181254a7Smrg! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14181254a7Smrg! GNU General Public License for more details.
15181254a7Smrg!
16181254a7Smrg! Under Section 7 of GPL version 3, you are granted additional
17181254a7Smrg! permissions described in the GCC Runtime Library Exception, version
18181254a7Smrg! 3.1, as published by the Free Software Foundation.
19181254a7Smrg!
20181254a7Smrg! You should have received a copy of the GNU General Public License and
21181254a7Smrg! a copy of the GCC Runtime Library Exception along with this program;
22181254a7Smrg! see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23181254a7Smrg! <http://www.gnu.org/licenses/>.
24181254a7Smrg!
25181254a7Smrg! WARNING:  This file should never be compiled with an option that changes
26181254a7Smrg! default logical kind from 4 to some other value or changes default integer
27*b1e83836Smrg! kind from 4 to some other value.
28181254a7Smrg!
29*b1e83836Smrg! There are four combinations of repeatable and image_distinct.  The
30*b1e83836Smrg! language below is from the F2018 standard (actually, J3/18-007r1).
31181254a7Smrg!
32*b1e83836Smrg! This routine is only used for non-coarray programs or with programs
33*b1e83836Smrg! compiled with -fcoarray=single.  Use of -fcoarray=lib or -fcoarray=shared
34*b1e83836Smrg! requires different routines due to the need for communication between
35*b1e83836Smrg! images under case(iv).
36181254a7Smrg!
37*b1e83836Smrg! Technically, neither image_distinct nor image_num are now needed.  The
38*b1e83836Smrg! interface to _gfortran_random_init() is maintained for libgfortran ABI.
39*b1e83836Smrg! Note, the Fortran standard requires the image_distinct argument, so
40*b1e83836Smrg! it will always have a valid value, and the frontend generates an value
41*b1e83836Smrg! of 0 for image_num.
42181254a7Smrg!
43*b1e83836Smrgimpure subroutine _gfortran_random_init(repeatable, image_distinct, image_num)
44181254a7Smrg
45181254a7Smrg   implicit none
46181254a7Smrg
47181254a7Smrg   logical, value, intent(in) :: repeatable
48181254a7Smrg   logical, value, intent(in) :: image_distinct
49*b1e83836Smrg   integer, value, intent(in) :: image_num
50181254a7Smrg
51181254a7Smrg   logical, save :: once = .true.
52*b1e83836Smrg   integer :: nseed, lcg_seed
53181254a7Smrg   integer, save, allocatable :: seed(:)
54181254a7Smrg
55*b1e83836Smrg   if (repeatable) then
56181254a7Smrg      if (once) then
57181254a7Smrg         once = .false.
58181254a7Smrg         call random_seed(size=nseed)
59181254a7Smrg         allocate(seed(nseed))
60*b1e83836Smrg         lcg_seed = 57911963
61*b1e83836Smrg         call _gfortran_lcg(seed)
62*b1e83836Smrg      end if
63*b1e83836Smrg      call random_seed(put=seed)
64*b1e83836Smrg   else
65*b1e83836Smrg      call random_seed()
66181254a7Smrg      !
67*b1e83836Smrg      ! This cannot happen; but, prevent gfortran complaining about
68*b1e83836Smrg      ! unused variables.
69181254a7Smrg      !
70*b1e83836Smrg      if (image_num > 2) then
71*b1e83836Smrg         block
72*b1e83836Smrg            use iso_fortran_env, only : error_unit
73*b1e83836Smrg            write(error_unit, '(A)') 'whoops: random_init(.false., .false.)'
74*b1e83836Smrg            if (image_distinct) error stop image_num + 1
75*b1e83836Smrg            error stop image_num
76*b1e83836Smrg         end block
77*b1e83836Smrg      end if
78181254a7Smrg   end if
79181254a7Smrg
80*b1e83836Smrg   contains
81*b1e83836Smrg      !
82*b1e83836Smrg      ! SK Park and KW Miller, ``Random number generators: good ones are hard
83*b1e83836Smrg      ! to find,'' Comm. ACM, 31(10), 1192--1201, (1988).
84*b1e83836Smrg      !
85*b1e83836Smrg      ! Implementation of a prime modulus multiplicative linear congruential
86*b1e83836Smrg      ! generator, which avoids overflow and provides the full period.
87*b1e83836Smrg      !
88*b1e83836Smrg      impure elemental subroutine _gfortran_lcg(i)
89*b1e83836Smrg         implicit none
90*b1e83836Smrg         integer, intent(out) :: i
91*b1e83836Smrg         integer, parameter :: a = 16807     ! Multiplier
92*b1e83836Smrg         integer, parameter :: m = huge(a)   ! Modulus
93*b1e83836Smrg         integer, parameter :: q = 127773    ! Quotient to avoid overflow
94*b1e83836Smrg         integer, parameter :: r = 2836      ! Remainder to avoid overflow
95*b1e83836Smrg         lcg_seed = a * mod(lcg_seed, q) - r * (lcg_seed / q)
96*b1e83836Smrg         if (lcg_seed <= 0) lcg_seed = lcg_seed + m
97*b1e83836Smrg         i = lcg_seed
98*b1e83836Smrg      end subroutine _gfortran_lcg
99181254a7Smrg
100181254a7Smrgend subroutine _gfortran_random_init
101