FV3 Bundle
MersenneTwister.F90
Go to the documentation of this file.
1 ! Fortran-95 implementation of the Mersenne Twister 19937, following
2 ! the C implementation described below (code mt19937ar-cok.c, dated 2002/2/10),
3 ! adapted cosmetically by making the names more general.
4 ! Users must declare one or more variables of type randomNumberSequence in the calling
5 ! procedure which are then initialized using a required seed. If the
6 ! variable is not initialized the random numbers will all be 0.
7 ! For example:
8 ! program testRandoms
9 ! use RandomNumbers
10 ! type(randomNumberSequence) :: randomNumbers
11 ! integer :: i
12 !
13 ! randomNumbers = new_RandomNumberSequence(seed = 100)
14 ! do i = 1, 10
15 ! print ('(f12.10, 2x)'), getRandomReal(randomNumbers)
16 ! end do
17 ! end program testRandoms
18 !
19 ! Fortran-95 implementation by
20 ! Robert Pincus
21 ! NOAA-CIRES Climate Diagnostics Center
22 ! Boulder, CO 80305
23 ! email: Robert.Pincus@colorado.edu
24 !
25 ! This documentation in the original C program reads:
26 ! -------------------------------------------------------------
27 ! A C-program for MT19937, with initialization improved 2002/2/10.
28 ! Coded by Takuji Nishimura and Makoto Matsumoto.
29 ! This is a faster version by taking Shawn Cokus's optimization,
30 ! Matthe Bellew's simplification, Isaku Wada's real version.
31 !
32 ! Before using, initialize the state by using init_genrand(seed)
33 ! or init_by_array(init_key, key_length).
34 !
35 ! Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
36 ! All rights reserved.
37 !
38 ! Redistribution and use in source and binary forms, with or without
39 ! modification, are permitted provided that the following conditions
40 ! are met:
41 !
42 ! 1. Redistributions of source code must retain the above copyright
43 ! notice, this list of conditions and the following disclaimer.
44 !
45 ! 2. Redistributions in binary form must reproduce the above copyright
46 ! notice, this list of conditions and the following disclaimer in the
47 ! documentation and/or other materials provided with the distribution.
48 !
49 ! 3. The names of its contributors may not be used to endorse or promote
50 ! products derived from this software without specific prior written
51 ! permission.
52 !
53 ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
54 ! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
55 ! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
56 ! A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
57 ! CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
58 ! EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
59 ! PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
60 ! PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
61 ! LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
62 ! NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
63 ! SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64 !
65 !
66 ! Any feedback is very welcome.
67 ! http://www.math.keio.ac.jp/matumoto/emt.html
68 ! email: matumoto@math.keio.ac.jp
69 ! -------------------------------------------------------------
70 
72 ! -------------------------------------------------------------
73  implicit none
74  private
75 
76  ! Algorithm parameters
77  ! -------
78  ! Period parameters
79  integer, parameter :: blocksize = 624, &
80  m = 397, &
81  matrix_a = -1727483681, & ! constant vector a (0x9908b0dfUL)
82  umask = -2147483648_8, & ! most significant w-r bits (0x80000000UL)
83  lmask = 2147483647 ! least significant r bits (0x7fffffffUL)
84  ! Tempering parameters
85  integer, parameter :: tmaskb= -1658038656, & ! (0x9d2c5680UL)
86  tmaskc= -272236544 ! (0xefc60000UL)
87  ! -------
88 
89  ! The type containing the state variable
91  integer :: currentelement ! = blockSize
92  integer, dimension(0:blockSize -1) :: state ! = 0
93  end type randomnumbersequence
94 
96  module procedure initialize_scalar, initialize_vector
97  end interface new_randomnumbersequence
98 
99  public :: randomnumbersequence
102 ! -------------------------------------------------------------
103 contains
104  ! -------------------------------------------------------------
105  ! Private functions
106  ! ---------------------------
107  function mixbits(u, v)
108  integer, intent( in) :: u, v
109  integer :: mixbits
110 
111  mixbits = ior(iand(u, umask), iand(v, lmask))
112  end function mixbits
113  ! ---------------------------
114  function twist(u, v)
115  integer, intent( in) :: u, v
116  integer :: twist
117 
118  ! Local variable
119  integer, parameter, dimension(0:1) :: t_matrix = (/ 0, matrix_a /)
120 
121  twist = ieor(ishft(mixbits(u, v), -1), t_matrix(iand(v, 1)))
122  twist = ieor(ishft(mixbits(u, v), -1), t_matrix(iand(v, 1)))
123  end function twist
124  ! ---------------------------
125  subroutine nextstate(twister)
126  type(randomNumberSequence), intent(inout) :: twister
127 
128  ! Local variables
129  integer :: k
130 
131  do k = 0, blocksize - m - 1
132  twister%state(k) = ieor(twister%state(k + m), &
133  twist(twister%state(k), twister%state(k + 1)))
134  end do
135  do k = blocksize - m, blocksize - 2
136  twister%state(k) = ieor(twister%state(k + m - blocksize), &
137  twist(twister%state(k), twister%state(k + 1)))
138  end do
139  twister%state(blocksize - 1) = ieor(twister%state(m - 1), &
140  twist(twister%state(blocksize - 1), twister%state(0)))
141  twister%currentElement = 0
142 
143  end subroutine nextstate
144  ! ---------------------------
145  elemental function temper(y)
146  integer, intent(in) :: y
147  integer :: temper
148 
149  integer :: x
150 
151  ! Tempering
152  x = ieor(y, ishft(y, -11))
153  x = ieor(x, iand(ishft(x, 7), tmaskb))
154  x = ieor(x, iand(ishft(x, 15), tmaskc))
155  temper = ieor(x, ishft(x, -18))
156  end function temper
157  ! -------------------------------------------------------------
158  ! Public (but hidden) functions
159  ! --------------------
160  function initialize_scalar(seed) result(twister)
161  integer, intent(in ) :: seed
162  type(randomnumbersequence) :: twister
163 
164  integer :: i
165  ! See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. In the previous versions,
166  ! MSBs of the seed affect only MSBs of the array state[].
167  ! 2002/01/09 modified by Makoto Matsumoto
168 
169  twister%state(0) = iand(seed, -1)
170  do i = 1, blocksize - 1 ! ubound(twister%state)
171  twister%state(i) = 1812433253 * ieor(twister%state(i-1), &
172  ishft(twister%state(i-1), -30)) + i
173  twister%state(i) = iand(twister%state(i), -1) ! for >32 bit machines
174  end do
175  twister%currentElement = blocksize
176  end function initialize_scalar
177  ! -------------------------------------------------------------
178  function initialize_vector(seed) result(twister)
179  integer, dimension(0:), intent(in) :: seed
180  type(randomnumbersequence) :: twister
181 
182  integer :: i, j, k, nfirstloop, nwraps
183 
184  nwraps = 0
185  twister = initialize_scalar(19650218)
186 
187  nfirstloop = max(blocksize, size(seed))
188  do k = 1, nfirstloop
189  i = mod(k + nwraps, blocksize)
190  j = mod(k - 1, size(seed))
191  if(i == 0) then
192  twister%state(i) = twister%state(blocksize - 1)
193  twister%state(1) = ieor(twister%state(1), &
194  ieor(twister%state(1-1), &
195  ishft(twister%state(1-1), -30)) * 1664525) + &
196  seed(j) + j ! Non-linear
197  twister%state(i) = iand(twister%state(i), -1) ! for >32 bit machines
198  nwraps = nwraps + 1
199  else
200  twister%state(i) = ieor(twister%state(i), &
201  ieor(twister%state(i-1), &
202  ishft(twister%state(i-1), -30)) * 1664525) + &
203  seed(j) + j ! Non-linear
204  twister%state(i) = iand(twister%state(i), -1) ! for >32 bit machines
205  end if
206  end do
207 
208  !
209  ! Walk through the state array, beginning where we left off in the block above
210  !
211  do i = mod(nfirstloop, blocksize) + nwraps + 1, blocksize - 1
212  twister%state(i) = ieor(twister%state(i), &
213  ieor(twister%state(i-1), &
214  ishft(twister%state(i-1), -30)) * 1566083941) - i ! Non-linear
215  twister%state(i) = iand(twister%state(i), -1) ! for >32 bit machines
216  end do
217 
218  twister%state(0) = twister%state(blocksize - 1)
219 
220  do i = 1, mod(nfirstloop, blocksize) + nwraps
221  twister%state(i) = ieor(twister%state(i), &
222  ieor(twister%state(i-1), &
223  ishft(twister%state(i-1), -30)) * 1566083941) - i ! Non-linear
224  twister%state(i) = iand(twister%state(i), -1) ! for >32 bit machines
225  end do
226 
227  twister%state(0) = umask
228  twister%currentElement = blocksize
229 
230  end function initialize_vector
231  ! -------------------------------------------------------------
232  ! Public functions
233  ! --------------------
234  function getrandomint(twister)
235  type(randomnumbersequence), intent(inout) :: twister
236  integer :: getrandomint
237  ! Generate a random integer on the interval [0,0xffffffff]
238  ! Equivalent to genrand_int32 in the C code.
239  ! Fortran doesn't have a type that's unsigned like C does,
240  ! so this is integers in the range -2**31 - 2**31
241  ! All functions for getting random numbers call this one,
242  ! then manipulate the result
243 
244  if(twister%currentElement >= blocksize) call nextstate(twister)
245 
246  getrandomint = temper(twister%state(twister%currentElement))
247  twister%currentElement = twister%currentElement + 1
248 
249  end function getrandomint
250  ! --------------------
251  function getrandompositiveint(twister)
252  type(randomnumbersequence), intent(inout) :: twister
253  integer :: getrandompositiveint
254  ! Generate a random integer on the interval [0,0x7fffffff]
255  ! or [0,2**31]
256  ! Equivalent to genrand_int31 in the C code.
257 
258  ! Local integers
259  integer :: localint
260 
261  localint = getrandomint(twister)
262  getrandompositiveint = ishft(localint, -1)
263 
264  end function getrandompositiveint
265  ! --------------------
266  function getrandomreal(twister)
267  type(randomnumbersequence), intent(inout) :: twister
268  double precision :: getrandomreal
269  ! Generate a random number on [0,1]
270  ! Equivalent to genrand_real1 in the C code
271  ! The result is stored as double precision but has 32 bit resolution
272 
273  integer :: localint
274 
275  localint = getrandomint(twister)
276  if(localint < 0) then
277  getrandomreal = dble(localint + 2.0d0**32)/(2.0d0**32 - 1.0d0)
278  else
279  getrandomreal = dble(localint )/(2.0d0**32 - 1.0d0)
280  end if
281  end function getrandomreal
282  ! --------------------
283  subroutine finalize_randomnumbersequence(twister)
284  type(randomnumbersequence), intent(inout) :: twister
285 
286  twister%currentElement = blocksize
287  twister%state(:) = 0
288  end subroutine finalize_randomnumbersequence
289  ! --------------------
290 end module mersennetwister_mod
291 
integer function twist(u, v)
integer, parameter tmaskc
subroutine, public finalize_randomnumbersequence(twister)
integer, parameter blocksize
integer function, public getrandomint(twister)
integer, parameter lmask
integer, parameter matrix_a
type(randomnumbersequence) function initialize_vector(seed)
double precision function, public getrandomreal(twister)
integer, parameter m
integer function, public getrandompositiveint(twister)
type(randomnumbersequence) function initialize_scalar(seed)
#define max(a, b)
Definition: mosaic_util.h:33
integer function mixbits(u, v)
integer, parameter tmaskb
subroutine nextstate(twister)
integer, parameter umask
elemental integer function temper(y)