Octopus
quickrnd.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2024 M. Marques, A. Castro, A. Rubio, G. Bertsch, X. Andrade, A. Buccheri, H. Menke
2!!
3!! This program is free software; you can redistribute it and/or modify
4!! it under the terms of the GNU General Public License as published by
5!! the Free Software Foundation; either version 2, or (at your option)
6!! any later version.
7!!
8!! This program is distributed in the hope that it will be useful,
9!! but WITHOUT ANY WARRANTY; without even the implied warranty of
10!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11!! GNU General Public License for more details.
12!!
13!! You should have received a copy of the GNU General Public License
14!! along with this program; if not, write to the Free Software
15!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16!! 02110-1301, USA.
17!!
18
19#include "global.h"
20
21module quickrnd_oct_m
22 use, intrinsic :: iso_fortran_env
23 use debug_oct_m
24 use global_oct_m
27
28 implicit none
29
30 private
31 public :: &
32 quickrnd, &
33 shiftseed, &
35
36 ! xorshift64 needs a good seed, in particular it cannot be seeded with 0.
37 ! These seeds are generated with the splitmix64 generator and have a
38 ! reasonable amount of entropy.
39 integer(int64), parameter, public :: &
40 splitmix64_123 = int(z'B4DC9BD462DE412B', int64), & ! splitmix64(123)
41 splitmix64_321 = int(z'E95F1C4EFCF85DEE', int64) ! splitmix64(321)
42
43 interface quickrnd
45 end interface quickrnd
46
47contains
48
53 function xorshift64(x) result(res)
54 integer(int64), intent(inout) :: x
55 integer(int64) :: res
56
57 assert(x /= 0_int64)
58
59 x = ieor(x, shiftl(x, 13))
60 x = ieor(x, shiftr(x, 7))
61 x = ieor(x, shiftl(x, 17))
62
63 res = x
64 end function xorshift64
65
74 function to_double(x) result(d)
75 integer(int64), intent(in) :: x
76 real(real64) :: d
77 real(real64), parameter :: two_pow_minus_53 = real(z'3CA0000000000000', real64)
78
79 d = real(shiftr(x, 11), real64) * two_pow_minus_53
80 end function to_double
81
82 ! ---------------------------------------------------------
83
84 subroutine dquickrnd_single(iseed, rnd)
85 integer(int64), intent(inout) :: iseed
86 real(real64), intent(out) :: rnd
87
88 ! no PUSH_SUB, called too often
89
90 rnd = to_double(xorshift64(iseed))
91
92 end subroutine dquickrnd_single
93
94 ! ---------------------------------------------------------
95
96 subroutine dquickrnd_array(iseed, nn, rnd)
97 integer(int64), intent(inout) :: iseed
98 integer, intent(in) :: nn
99 real(real64), intent(inout) :: rnd(:)
100
101 integer :: ii
102
103 push_sub(quickrnd_array)
104
105 do ii = 1, nn
106 rnd(ii) = to_double(xorshift64(iseed))
107 end do
108
109 pop_sub(quickrnd_array)
110
111 end subroutine dquickrnd_array
112
113 ! ---------------------------------------------------------
114
115 subroutine zquickrnd_array(iseed, nn, rnd)
116 integer(int64), intent(inout) :: iseed
117 integer, intent(in) :: nn
118 complex(real64), intent(inout) :: rnd(:)
119
120 real(real64), parameter :: inv_sqrt2 = 1.0_real64 / sqrt(m_two)
121 real(real64) :: re, im
122 integer :: ii
123
124 push_sub(quickrnd_array)
125
126 do ii = 1, nn
127 re = to_double(xorshift64(iseed))
128 im = to_double(xorshift64(iseed))
129 rnd(ii) = cmplx(re, im, real64) * inv_sqrt2
130 end do
131
132 pop_sub(quickrnd_array)
133
134 end subroutine zquickrnd_array
135
136 ! ---------------------------------------------------------
137
138 subroutine shiftseed(iseed, n)
139 integer(int64), intent(inout) :: iseed
140 integer(int64), intent(in) :: n
141
142 integer(int64) :: discard
143 integer(int64) :: ii
144
145 push_sub(shiftseed)
146
147 do ii = 1, n
148 discard = xorshift64(iseed)
149 end do
150
151 pop_sub(shiftseed)
152
153 end subroutine shiftseed
154
155
166 function random_integer_in_range(x_min, x_max, seed) result(rand)
167 integer(int64), intent(in ) :: x_min, x_max
168 integer(int64), intent(inout) :: seed
169 integer(int64) :: rand
170
171 integer(int64) :: range
172
173 assert(seed /= 0_int64)
174 seed = xorshift64(seed)
175 if (seed < 0_int64) seed = -seed ! Enforce a positive result
176 range = x_max - x_min + 1_int64
177 rand = x_min + mod(seed, range)
178
180
181
187 subroutine fisher_yates_shuffle(m, n, seed, values)
188 integer(int32), intent(in ) :: m
189 integer(int64), intent(in ) :: n
190 integer(int64), intent(inout) :: seed
191 integer(int64), intent( out) :: values(:)
192
193 integer(int64), allocatable :: indices(:)
194 integer(int64) :: i, j, temp
195
196 push_sub(fisher_yates_shuffle)
197
198 safe_allocate(indices(1:n))
199 do j = 1, n
200 indices(j) = j
201 end do
202
203 do i = 1, m
204 j = random_integer_in_range(i, n, seed)
205 ! Perform the swap
206 temp = indices(i)
207 indices(i) = indices(j)
208 indices(j) = temp
209 values(i) = indices(i)
210 end do
211
212 values(m) = indices(m)
213 safe_deallocate_a(indices)
214
215 pop_sub(fisher_yates_shuffle)
216
217 end subroutine fisher_yates_shuffle
218
219end module quickrnd_oct_m
220
221!! Local Variables:
222!! mode: f90
223!! coding: utf-8
224!! End:
int rand(void)
Definition: getopt_f.c:1459
double sqrt(double __x) __attribute__((__nothrow__
real(real64), parameter, public m_two
Definition: global.F90:193
subroutine dquickrnd_array(iseed, nn, rnd)
Definition: quickrnd.F90:192
real(real64) function to_double(x)
Generating uniform doubles in the unit interval.
Definition: quickrnd.F90:170
integer(int64), parameter, public splitmix64_321
Definition: quickrnd.F90:134
subroutine, public shiftseed(iseed, n)
Definition: quickrnd.F90:234
integer(int64) function random_integer_in_range(x_min, x_max, seed)
Generate a random int64 in the range .
Definition: quickrnd.F90:262
subroutine, public fisher_yates_shuffle(m, n, seed, values)
Return m random numbers from a range of with no replacement.
Definition: quickrnd.F90:283
subroutine dquickrnd_single(iseed, rnd)
Definition: quickrnd.F90:180
integer(int64) function xorshift64(x)
xorshift64 pseudorandom number generator
Definition: quickrnd.F90:149
subroutine zquickrnd_array(iseed, nn, rnd)
Definition: quickrnd.F90:211