random.c revision 1.1.1.4 1 1.1 mrg /* Implementation of the RANDOM intrinsics
2 1.1.1.4 mrg Copyright (C) 2002-2024 Free Software Foundation, Inc.
3 1.1 mrg Contributed by Lars Segerlund <seger (at) linuxmail.org>,
4 1.1 mrg Steve Kargl and Janne Blomqvist.
5 1.1 mrg
6 1.1 mrg This file is part of the GNU Fortran runtime library (libgfortran).
7 1.1 mrg
8 1.1 mrg Libgfortran is free software; you can redistribute it and/or
9 1.1 mrg modify it under the terms of the GNU General Public
10 1.1 mrg License as published by the Free Software Foundation; either
11 1.1 mrg version 3 of the License, or (at your option) any later version.
12 1.1 mrg
13 1.1 mrg Ligbfortran is distributed in the hope that it will be useful,
14 1.1 mrg but WITHOUT ANY WARRANTY; without even the implied warranty of
15 1.1 mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 1.1 mrg GNU General Public License for more details.
17 1.1 mrg
18 1.1 mrg Under Section 7 of GPL version 3, you are granted additional
19 1.1 mrg permissions described in the GCC Runtime Library Exception, version
20 1.1 mrg 3.1, as published by the Free Software Foundation.
21 1.1 mrg
22 1.1 mrg You should have received a copy of the GNU General Public License and
23 1.1 mrg a copy of the GCC Runtime Library Exception along with this program;
24 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 1.1 mrg <http://www.gnu.org/licenses/>. */
26 1.1 mrg
27 1.1 mrg /* For rand_s. */
28 1.1 mrg #define _CRT_RAND_S
29 1.1 mrg
30 1.1 mrg #include "libgfortran.h"
31 1.1 mrg #include <gthr.h>
32 1.1 mrg #include <string.h>
33 1.1 mrg
34 1.1 mrg #ifdef HAVE_UNISTD_H
35 1.1 mrg #include <unistd.h>
36 1.1 mrg #endif
37 1.1 mrg #include <sys/stat.h>
38 1.1 mrg #include <fcntl.h>
39 1.1 mrg #include "time_1.h"
40 1.1 mrg #ifdef HAVE_SYS_RANDOM_H
41 1.1 mrg #include <sys/random.h>
42 1.1 mrg #endif
43 1.1 mrg
44 1.1 mrg #ifdef __MINGW32__
45 1.1 mrg #define HAVE_GETPID 1
46 1.1 mrg #include <process.h>
47 1.1 mrg #include <_mingw.h> /* For __MINGW64_VERSION_MAJOR */
48 1.1 mrg #endif
49 1.1 mrg
50 1.1 mrg extern void random_r4 (GFC_REAL_4 *);
51 1.1 mrg iexport_proto(random_r4);
52 1.1 mrg
53 1.1 mrg extern void random_r8 (GFC_REAL_8 *);
54 1.1 mrg iexport_proto(random_r8);
55 1.1 mrg
56 1.1 mrg extern void arandom_r4 (gfc_array_r4 *);
57 1.1 mrg export_proto(arandom_r4);
58 1.1 mrg
59 1.1 mrg extern void arandom_r8 (gfc_array_r8 *);
60 1.1 mrg export_proto(arandom_r8);
61 1.1 mrg
62 1.1 mrg #ifdef HAVE_GFC_REAL_10
63 1.1 mrg
64 1.1 mrg extern void random_r10 (GFC_REAL_10 *);
65 1.1 mrg iexport_proto(random_r10);
66 1.1 mrg
67 1.1 mrg extern void arandom_r10 (gfc_array_r10 *);
68 1.1 mrg export_proto(arandom_r10);
69 1.1 mrg
70 1.1 mrg #endif
71 1.1 mrg
72 1.1 mrg #ifdef HAVE_GFC_REAL_16
73 1.1 mrg
74 1.1 mrg extern void random_r16 (GFC_REAL_16 *);
75 1.1 mrg iexport_proto(random_r16);
76 1.1 mrg
77 1.1 mrg extern void arandom_r16 (gfc_array_r16 *);
78 1.1 mrg export_proto(arandom_r16);
79 1.1 mrg
80 1.1 mrg #endif
81 1.1 mrg
82 1.1.1.3 mrg #ifdef HAVE_GFC_REAL_17
83 1.1.1.3 mrg
84 1.1.1.3 mrg extern void random_r17 (GFC_REAL_17 *);
85 1.1.1.3 mrg iexport_proto(random_r17);
86 1.1.1.3 mrg
87 1.1.1.3 mrg extern void arandom_r17 (gfc_array_r17 *);
88 1.1.1.3 mrg export_proto(arandom_r17);
89 1.1.1.3 mrg
90 1.1.1.3 mrg #endif
91 1.1.1.3 mrg
92 1.1 mrg #ifdef __GTHREAD_MUTEX_INIT
93 1.1 mrg static __gthread_mutex_t random_lock = __GTHREAD_MUTEX_INIT;
94 1.1 mrg #else
95 1.1 mrg static __gthread_mutex_t random_lock;
96 1.1 mrg #endif
97 1.1 mrg
98 1.1 mrg /* Helper routines to map a GFC_UINTEGER_* to the corresponding
99 1.1 mrg GFC_REAL_* types in the range of [0,1). If GFC_REAL_*_RADIX are 2
100 1.1 mrg or 16, respectively, we mask off the bits that don't fit into the
101 1.1 mrg correct GFC_REAL_*, convert to the real type, then multiply by the
102 1.1 mrg correct offset. */
103 1.1 mrg
104 1.1 mrg
105 1.1 mrg static void
106 1.1 mrg rnumber_4 (GFC_REAL_4 *f, GFC_UINTEGER_4 v)
107 1.1 mrg {
108 1.1 mrg GFC_UINTEGER_4 mask;
109 1.1 mrg #if GFC_REAL_4_RADIX == 2
110 1.1 mrg mask = ~ (GFC_UINTEGER_4) 0u << (32 - GFC_REAL_4_DIGITS);
111 1.1 mrg #elif GFC_REAL_4_RADIX == 16
112 1.1 mrg mask = ~ (GFC_UINTEGER_4) 0u << ((8 - GFC_REAL_4_DIGITS) * 4);
113 1.1 mrg #else
114 1.1 mrg #error "GFC_REAL_4_RADIX has unknown value"
115 1.1 mrg #endif
116 1.1 mrg v = v & mask;
117 1.1 mrg *f = (GFC_REAL_4) v * GFC_REAL_4_LITERAL(0x1.p-32);
118 1.1 mrg }
119 1.1 mrg
120 1.1 mrg static void
121 1.1 mrg rnumber_8 (GFC_REAL_8 *f, GFC_UINTEGER_8 v)
122 1.1 mrg {
123 1.1 mrg GFC_UINTEGER_8 mask;
124 1.1 mrg #if GFC_REAL_8_RADIX == 2
125 1.1 mrg mask = ~ (GFC_UINTEGER_8) 0u << (64 - GFC_REAL_8_DIGITS);
126 1.1 mrg #elif GFC_REAL_8_RADIX == 16
127 1.1 mrg mask = ~ (GFC_UINTEGER_8) 0u << (16 - GFC_REAL_8_DIGITS) * 4);
128 1.1 mrg #else
129 1.1 mrg #error "GFC_REAL_8_RADIX has unknown value"
130 1.1 mrg #endif
131 1.1 mrg v = v & mask;
132 1.1 mrg *f = (GFC_REAL_8) v * GFC_REAL_8_LITERAL(0x1.p-64);
133 1.1 mrg }
134 1.1 mrg
135 1.1 mrg #ifdef HAVE_GFC_REAL_10
136 1.1 mrg
137 1.1 mrg static void
138 1.1 mrg rnumber_10 (GFC_REAL_10 *f, GFC_UINTEGER_8 v)
139 1.1 mrg {
140 1.1 mrg GFC_UINTEGER_8 mask;
141 1.1 mrg #if GFC_REAL_10_RADIX == 2
142 1.1 mrg mask = ~ (GFC_UINTEGER_8) 0u << (64 - GFC_REAL_10_DIGITS);
143 1.1 mrg #elif GFC_REAL_10_RADIX == 16
144 1.1 mrg mask = ~ (GFC_UINTEGER_10) 0u << ((16 - GFC_REAL_10_DIGITS) * 4);
145 1.1 mrg #else
146 1.1 mrg #error "GFC_REAL_10_RADIX has unknown value"
147 1.1 mrg #endif
148 1.1 mrg v = v & mask;
149 1.1 mrg *f = (GFC_REAL_10) v * GFC_REAL_10_LITERAL(0x1.p-64);
150 1.1 mrg }
151 1.1 mrg #endif
152 1.1 mrg
153 1.1 mrg #ifdef HAVE_GFC_REAL_16
154 1.1 mrg
155 1.1 mrg /* For REAL(KIND=16), we only need to mask off the lower bits. */
156 1.1 mrg
157 1.1 mrg static void
158 1.1 mrg rnumber_16 (GFC_REAL_16 *f, GFC_UINTEGER_8 v1, GFC_UINTEGER_8 v2)
159 1.1 mrg {
160 1.1 mrg GFC_UINTEGER_8 mask;
161 1.1 mrg #if GFC_REAL_16_RADIX == 2
162 1.1 mrg mask = ~ (GFC_UINTEGER_8) 0u << (128 - GFC_REAL_16_DIGITS);
163 1.1 mrg #elif GFC_REAL_16_RADIX == 16
164 1.1 mrg mask = ~ (GFC_UINTEGER_8) 0u << ((32 - GFC_REAL_16_DIGITS) * 4);
165 1.1 mrg #else
166 1.1 mrg #error "GFC_REAL_16_RADIX has unknown value"
167 1.1 mrg #endif
168 1.1 mrg v2 = v2 & mask;
169 1.1 mrg *f = (GFC_REAL_16) v1 * GFC_REAL_16_LITERAL(0x1.p-64)
170 1.1 mrg + (GFC_REAL_16) v2 * GFC_REAL_16_LITERAL(0x1.p-128);
171 1.1 mrg }
172 1.1 mrg #endif
173 1.1 mrg
174 1.1.1.3 mrg #ifdef HAVE_GFC_REAL_17
175 1.1.1.3 mrg
176 1.1.1.3 mrg /* For REAL(KIND=16), we only need to mask off the lower bits. */
177 1.1.1.3 mrg
178 1.1.1.3 mrg static void
179 1.1.1.3 mrg rnumber_17 (GFC_REAL_17 *f, GFC_UINTEGER_8 v1, GFC_UINTEGER_8 v2)
180 1.1.1.3 mrg {
181 1.1.1.3 mrg GFC_UINTEGER_8 mask;
182 1.1.1.3 mrg #if GFC_REAL_17_RADIX == 2
183 1.1.1.3 mrg mask = ~ (GFC_UINTEGER_8) 0u << (128 - GFC_REAL_17_DIGITS);
184 1.1.1.3 mrg #elif GFC_REAL_17_RADIX == 16
185 1.1.1.3 mrg mask = ~ (GFC_UINTEGER_8) 0u << ((32 - GFC_REAL_17_DIGITS) * 4);
186 1.1.1.3 mrg #else
187 1.1.1.3 mrg #error "GFC_REAL_17_RADIX has unknown value"
188 1.1.1.3 mrg #endif
189 1.1.1.3 mrg v2 = v2 & mask;
190 1.1.1.3 mrg *f = (GFC_REAL_17) v1 * GFC_REAL_17_LITERAL(0x1.p-64)
191 1.1.1.3 mrg + (GFC_REAL_17) v2 * GFC_REAL_17_LITERAL(0x1.p-128);
192 1.1.1.3 mrg }
193 1.1.1.3 mrg #endif
194 1.1.1.3 mrg
195 1.1 mrg
196 1.1 mrg /*
197 1.1 mrg
198 1.1.1.2 mrg We use the xoshiro256** generator, a fast high-quality generator
199 1.1 mrg that:
200 1.1 mrg
201 1.1 mrg - passes TestU1 without any failures
202 1.1 mrg
203 1.1 mrg - provides a "jump" function making it easy to provide many
204 1.1 mrg independent parallel streams.
205 1.1 mrg
206 1.1.1.2 mrg - Long period of 2**256 - 1
207 1.1 mrg
208 1.1 mrg A description can be found at
209 1.1 mrg
210 1.1.1.2 mrg http://prng.di.unimi.it/
211 1.1 mrg
212 1.1 mrg or
213 1.1 mrg
214 1.1.1.2 mrg https://arxiv.org/abs/1805.01407
215 1.1 mrg
216 1.1 mrg The paper includes public domain source code which is the basis for
217 1.1 mrg the implementation below.
218 1.1 mrg
219 1.1 mrg */
220 1.1 mrg typedef struct
221 1.1 mrg {
222 1.1 mrg bool init;
223 1.1.1.2 mrg uint64_t s[4];
224 1.1 mrg }
225 1.1.1.2 mrg prng_state;
226 1.1 mrg
227 1.1 mrg
228 1.1.1.2 mrg /* master_state is the only variable protected by random_lock. */
229 1.1.1.2 mrg static prng_state master_state = { .init = false, .s = {
230 1.1.1.2 mrg 0xad63fa1ed3b55f36ULL, 0xd94473e78978b497ULL, 0xbc60592a98172477ULL,
231 1.1.1.2 mrg 0xa3de7c6e81265301ULL }
232 1.1 mrg };
233 1.1 mrg
234 1.1 mrg
235 1.1 mrg static __gthread_key_t rand_state_key;
236 1.1 mrg
237 1.1.1.2 mrg static prng_state*
238 1.1 mrg get_rand_state (void)
239 1.1 mrg {
240 1.1 mrg /* For single threaded apps. */
241 1.1.1.2 mrg static prng_state rand_state;
242 1.1 mrg
243 1.1 mrg if (__gthread_active_p ())
244 1.1 mrg {
245 1.1 mrg void* p = __gthread_getspecific (rand_state_key);
246 1.1 mrg if (!p)
247 1.1 mrg {
248 1.1.1.2 mrg p = xcalloc (1, sizeof (prng_state));
249 1.1 mrg __gthread_setspecific (rand_state_key, p);
250 1.1 mrg }
251 1.1 mrg return p;
252 1.1 mrg }
253 1.1 mrg else
254 1.1 mrg return &rand_state;
255 1.1 mrg }
256 1.1 mrg
257 1.1.1.2 mrg static inline uint64_t
258 1.1.1.2 mrg rotl (const uint64_t x, int k)
259 1.1.1.2 mrg {
260 1.1.1.2 mrg return (x << k) | (x >> (64 - k));
261 1.1.1.2 mrg }
262 1.1.1.2 mrg
263 1.1 mrg
264 1.1 mrg static uint64_t
265 1.1.1.2 mrg prng_next (prng_state* rs)
266 1.1 mrg {
267 1.1.1.2 mrg const uint64_t result = rotl(rs->s[1] * 5, 7) * 9;
268 1.1.1.2 mrg
269 1.1.1.2 mrg const uint64_t t = rs->s[1] << 17;
270 1.1.1.2 mrg
271 1.1.1.2 mrg rs->s[2] ^= rs->s[0];
272 1.1.1.2 mrg rs->s[3] ^= rs->s[1];
273 1.1.1.2 mrg rs->s[1] ^= rs->s[2];
274 1.1.1.2 mrg rs->s[0] ^= rs->s[3];
275 1.1.1.2 mrg
276 1.1.1.2 mrg rs->s[2] ^= t;
277 1.1.1.2 mrg
278 1.1.1.2 mrg rs->s[3] = rotl(rs->s[3], 45);
279 1.1.1.2 mrg
280 1.1.1.2 mrg return result;
281 1.1 mrg }
282 1.1 mrg
283 1.1 mrg
284 1.1 mrg /* This is the jump function for the generator. It is equivalent to
285 1.1.1.2 mrg 2^128 calls to prng_next(); it can be used to generate 2^128
286 1.1 mrg non-overlapping subsequences for parallel computations. */
287 1.1 mrg
288 1.1 mrg static void
289 1.1.1.2 mrg jump (prng_state* rs)
290 1.1 mrg {
291 1.1.1.2 mrg static const uint64_t JUMP[] = { 0x180ec6d33cfd0aba, 0xd5a61266f0c9392c, 0xa9582618e03fc9aa, 0x39abdc4529b1661c };
292 1.1 mrg
293 1.1.1.2 mrg uint64_t s0 = 0;
294 1.1.1.2 mrg uint64_t s1 = 0;
295 1.1.1.2 mrg uint64_t s2 = 0;
296 1.1.1.2 mrg uint64_t s3 = 0;
297 1.1 mrg for(size_t i = 0; i < sizeof JUMP / sizeof *JUMP; i++)
298 1.1.1.2 mrg for(int b = 0; b < 64; b++) {
299 1.1.1.2 mrg if (JUMP[i] & UINT64_C(1) << b) {
300 1.1.1.2 mrg s0 ^= rs->s[0];
301 1.1.1.2 mrg s1 ^= rs->s[1];
302 1.1.1.2 mrg s2 ^= rs->s[2];
303 1.1.1.2 mrg s3 ^= rs->s[3];
304 1.1 mrg }
305 1.1.1.2 mrg prng_next (rs);
306 1.1.1.2 mrg }
307 1.1.1.2 mrg
308 1.1.1.2 mrg rs->s[0] = s0;
309 1.1.1.2 mrg rs->s[1] = s1;
310 1.1.1.2 mrg rs->s[2] = s2;
311 1.1.1.2 mrg rs->s[3] = s3;
312 1.1 mrg }
313 1.1 mrg
314 1.1 mrg
315 1.1.1.2 mrg /* Splitmix64 recommended by xoshiro author for initializing. After
316 1.1 mrg getting one uint64_t value from the OS, this is used to fill in the
317 1.1.1.2 mrg rest of the xoshiro state. */
318 1.1 mrg
319 1.1 mrg static uint64_t
320 1.1 mrg splitmix64 (uint64_t x)
321 1.1 mrg {
322 1.1 mrg uint64_t z = (x += 0x9e3779b97f4a7c15);
323 1.1 mrg z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
324 1.1 mrg z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
325 1.1 mrg return z ^ (z >> 31);
326 1.1 mrg }
327 1.1 mrg
328 1.1 mrg
329 1.1.1.2 mrg /* Get some bytes from the operating system in order to seed
330 1.1 mrg the PRNG. */
331 1.1 mrg
332 1.1 mrg static int
333 1.1 mrg getosrandom (void *buf, size_t buflen)
334 1.1 mrg {
335 1.1 mrg /* rand_s is available in MinGW-w64 but not plain MinGW. */
336 1.1 mrg #if defined(__MINGW64_VERSION_MAJOR)
337 1.1 mrg unsigned int* b = buf;
338 1.1 mrg for (size_t i = 0; i < buflen / sizeof (unsigned int); i++)
339 1.1 mrg rand_s (&b[i]);
340 1.1 mrg return buflen;
341 1.1 mrg #else
342 1.1 mrg #ifdef HAVE_GETENTROPY
343 1.1 mrg if (getentropy (buf, buflen) == 0)
344 1.1 mrg return buflen;
345 1.1 mrg #endif
346 1.1 mrg int flags = O_RDONLY;
347 1.1 mrg #ifdef O_CLOEXEC
348 1.1 mrg flags |= O_CLOEXEC;
349 1.1 mrg #endif
350 1.1 mrg int fd = open("/dev/urandom", flags);
351 1.1 mrg if (fd != -1)
352 1.1 mrg {
353 1.1 mrg int res = read(fd, buf, buflen);
354 1.1 mrg close (fd);
355 1.1 mrg return res;
356 1.1 mrg }
357 1.1 mrg uint64_t seed = 0x047f7684e9fc949dULL;
358 1.1 mrg time_t secs;
359 1.1 mrg long usecs;
360 1.1 mrg if (gf_gettime (&secs, &usecs) == 0)
361 1.1 mrg {
362 1.1 mrg seed ^= secs;
363 1.1 mrg seed ^= usecs;
364 1.1 mrg }
365 1.1 mrg #ifdef HAVE_GETPID
366 1.1 mrg pid_t pid = getpid();
367 1.1 mrg seed ^= pid;
368 1.1 mrg #endif
369 1.1 mrg size_t size = buflen < sizeof (uint64_t) ? buflen : sizeof (uint64_t);
370 1.1 mrg memcpy (buf, &seed, size);
371 1.1 mrg return size;
372 1.1 mrg #endif /* __MINGW64_VERSION_MAJOR */
373 1.1 mrg }
374 1.1 mrg
375 1.1 mrg
376 1.1 mrg /* Initialize the random number generator for the current thread,
377 1.1 mrg using the master state and the number of times we must jump. */
378 1.1 mrg
379 1.1 mrg static void
380 1.1.1.2 mrg init_rand_state (prng_state* rs, const bool locked)
381 1.1 mrg {
382 1.1 mrg if (!locked)
383 1.1 mrg __gthread_mutex_lock (&random_lock);
384 1.1.1.2 mrg if (!master_state.init)
385 1.1 mrg {
386 1.1 mrg uint64_t os_seed;
387 1.1 mrg getosrandom (&os_seed, sizeof (os_seed));
388 1.1.1.2 mrg for (uint64_t i = 0; i < sizeof (master_state.s) / sizeof (uint64_t); i++)
389 1.1 mrg {
390 1.1.1.2 mrg os_seed = splitmix64 (os_seed);
391 1.1.1.2 mrg master_state.s[i] = os_seed;
392 1.1.1.2 mrg }
393 1.1.1.2 mrg master_state.init = true;
394 1.1 mrg }
395 1.1.1.2 mrg memcpy (&rs->s, master_state.s, sizeof (master_state.s));
396 1.1.1.2 mrg jump (&master_state);
397 1.1 mrg if (!locked)
398 1.1 mrg __gthread_mutex_unlock (&random_lock);
399 1.1 mrg rs->init = true;
400 1.1 mrg }
401 1.1 mrg
402 1.1 mrg
403 1.1 mrg /* This function produces a REAL(4) value from the uniform distribution
404 1.1 mrg with range [0,1). */
405 1.1 mrg
406 1.1 mrg void
407 1.1 mrg random_r4 (GFC_REAL_4 *x)
408 1.1 mrg {
409 1.1.1.2 mrg prng_state* rs = get_rand_state();
410 1.1 mrg
411 1.1 mrg if (unlikely (!rs->init))
412 1.1 mrg init_rand_state (rs, false);
413 1.1.1.2 mrg uint64_t r = prng_next (rs);
414 1.1 mrg /* Take the higher bits, ensuring that a stream of real(4), real(8),
415 1.1 mrg and real(10) will be identical (except for precision). */
416 1.1 mrg uint32_t high = (uint32_t) (r >> 32);
417 1.1 mrg rnumber_4 (x, high);
418 1.1 mrg }
419 1.1 mrg iexport(random_r4);
420 1.1 mrg
421 1.1 mrg /* This function produces a REAL(8) value from the uniform distribution
422 1.1 mrg with range [0,1). */
423 1.1 mrg
424 1.1 mrg void
425 1.1 mrg random_r8 (GFC_REAL_8 *x)
426 1.1 mrg {
427 1.1 mrg GFC_UINTEGER_8 r;
428 1.1.1.2 mrg prng_state* rs = get_rand_state();
429 1.1 mrg
430 1.1 mrg if (unlikely (!rs->init))
431 1.1 mrg init_rand_state (rs, false);
432 1.1.1.2 mrg r = prng_next (rs);
433 1.1 mrg rnumber_8 (x, r);
434 1.1 mrg }
435 1.1 mrg iexport(random_r8);
436 1.1 mrg
437 1.1 mrg #ifdef HAVE_GFC_REAL_10
438 1.1 mrg
439 1.1 mrg /* This function produces a REAL(10) value from the uniform distribution
440 1.1 mrg with range [0,1). */
441 1.1 mrg
442 1.1 mrg void
443 1.1 mrg random_r10 (GFC_REAL_10 *x)
444 1.1 mrg {
445 1.1 mrg GFC_UINTEGER_8 r;
446 1.1.1.2 mrg prng_state* rs = get_rand_state();
447 1.1 mrg
448 1.1 mrg if (unlikely (!rs->init))
449 1.1 mrg init_rand_state (rs, false);
450 1.1.1.2 mrg r = prng_next (rs);
451 1.1 mrg rnumber_10 (x, r);
452 1.1 mrg }
453 1.1 mrg iexport(random_r10);
454 1.1 mrg
455 1.1 mrg #endif
456 1.1 mrg
457 1.1 mrg /* This function produces a REAL(16) value from the uniform distribution
458 1.1 mrg with range [0,1). */
459 1.1 mrg
460 1.1 mrg #ifdef HAVE_GFC_REAL_16
461 1.1 mrg
462 1.1 mrg void
463 1.1 mrg random_r16 (GFC_REAL_16 *x)
464 1.1 mrg {
465 1.1 mrg GFC_UINTEGER_8 r1, r2;
466 1.1.1.2 mrg prng_state* rs = get_rand_state();
467 1.1 mrg
468 1.1 mrg if (unlikely (!rs->init))
469 1.1 mrg init_rand_state (rs, false);
470 1.1.1.2 mrg r1 = prng_next (rs);
471 1.1.1.2 mrg r2 = prng_next (rs);
472 1.1 mrg rnumber_16 (x, r1, r2);
473 1.1 mrg }
474 1.1 mrg iexport(random_r16);
475 1.1 mrg
476 1.1 mrg
477 1.1 mrg #endif
478 1.1 mrg
479 1.1.1.3 mrg /* This function produces a REAL(16) value from the uniform distribution
480 1.1.1.3 mrg with range [0,1). */
481 1.1.1.3 mrg
482 1.1.1.3 mrg #ifdef HAVE_GFC_REAL_17
483 1.1.1.3 mrg
484 1.1.1.3 mrg void
485 1.1.1.3 mrg random_r17 (GFC_REAL_17 *x)
486 1.1.1.3 mrg {
487 1.1.1.3 mrg GFC_UINTEGER_8 r1, r2;
488 1.1.1.3 mrg prng_state* rs = get_rand_state();
489 1.1.1.3 mrg
490 1.1.1.3 mrg if (unlikely (!rs->init))
491 1.1.1.3 mrg init_rand_state (rs, false);
492 1.1.1.3 mrg r1 = prng_next (rs);
493 1.1.1.3 mrg r2 = prng_next (rs);
494 1.1.1.3 mrg rnumber_17 (x, r1, r2);
495 1.1.1.3 mrg }
496 1.1.1.3 mrg iexport(random_r17);
497 1.1.1.3 mrg
498 1.1.1.3 mrg
499 1.1.1.3 mrg #endif
500 1.1.1.3 mrg
501 1.1 mrg /* This function fills a REAL(4) array with values from the uniform
502 1.1 mrg distribution with range [0,1). */
503 1.1 mrg
504 1.1 mrg void
505 1.1 mrg arandom_r4 (gfc_array_r4 *x)
506 1.1 mrg {
507 1.1 mrg index_type count[GFC_MAX_DIMENSIONS];
508 1.1 mrg index_type extent[GFC_MAX_DIMENSIONS];
509 1.1 mrg index_type stride[GFC_MAX_DIMENSIONS];
510 1.1 mrg index_type stride0;
511 1.1 mrg index_type dim;
512 1.1 mrg GFC_REAL_4 *dest;
513 1.1.1.2 mrg prng_state* rs = get_rand_state();
514 1.1 mrg
515 1.1 mrg dest = x->base_addr;
516 1.1 mrg
517 1.1 mrg dim = GFC_DESCRIPTOR_RANK (x);
518 1.1 mrg
519 1.1 mrg for (index_type n = 0; n < dim; n++)
520 1.1 mrg {
521 1.1 mrg count[n] = 0;
522 1.1 mrg stride[n] = GFC_DESCRIPTOR_STRIDE(x,n);
523 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(x,n);
524 1.1 mrg if (extent[n] <= 0)
525 1.1 mrg return;
526 1.1 mrg }
527 1.1 mrg
528 1.1 mrg stride0 = stride[0];
529 1.1 mrg
530 1.1 mrg if (unlikely (!rs->init))
531 1.1 mrg init_rand_state (rs, false);
532 1.1 mrg
533 1.1 mrg while (dest)
534 1.1 mrg {
535 1.1 mrg /* random_r4 (dest); */
536 1.1.1.2 mrg uint64_t r = prng_next (rs);
537 1.1 mrg uint32_t high = (uint32_t) (r >> 32);
538 1.1 mrg rnumber_4 (dest, high);
539 1.1 mrg
540 1.1 mrg /* Advance to the next element. */
541 1.1 mrg dest += stride0;
542 1.1 mrg count[0]++;
543 1.1 mrg /* Advance to the next source element. */
544 1.1 mrg index_type n = 0;
545 1.1 mrg while (count[n] == extent[n])
546 1.1 mrg {
547 1.1 mrg /* When we get to the end of a dimension, reset it and increment
548 1.1 mrg the next dimension. */
549 1.1 mrg count[n] = 0;
550 1.1 mrg /* We could precalculate these products, but this is a less
551 1.1 mrg frequently used path so probably not worth it. */
552 1.1 mrg dest -= stride[n] * extent[n];
553 1.1 mrg n++;
554 1.1 mrg if (n == dim)
555 1.1 mrg {
556 1.1 mrg dest = NULL;
557 1.1 mrg break;
558 1.1 mrg }
559 1.1 mrg else
560 1.1 mrg {
561 1.1 mrg count[n]++;
562 1.1 mrg dest += stride[n];
563 1.1 mrg }
564 1.1 mrg }
565 1.1 mrg }
566 1.1 mrg }
567 1.1 mrg
568 1.1 mrg /* This function fills a REAL(8) array with values from the uniform
569 1.1 mrg distribution with range [0,1). */
570 1.1 mrg
571 1.1 mrg void
572 1.1 mrg arandom_r8 (gfc_array_r8 *x)
573 1.1 mrg {
574 1.1 mrg index_type count[GFC_MAX_DIMENSIONS];
575 1.1 mrg index_type extent[GFC_MAX_DIMENSIONS];
576 1.1 mrg index_type stride[GFC_MAX_DIMENSIONS];
577 1.1 mrg index_type stride0;
578 1.1 mrg index_type dim;
579 1.1 mrg GFC_REAL_8 *dest;
580 1.1.1.2 mrg prng_state* rs = get_rand_state();
581 1.1 mrg
582 1.1 mrg dest = x->base_addr;
583 1.1 mrg
584 1.1 mrg dim = GFC_DESCRIPTOR_RANK (x);
585 1.1 mrg
586 1.1 mrg for (index_type n = 0; n < dim; n++)
587 1.1 mrg {
588 1.1 mrg count[n] = 0;
589 1.1 mrg stride[n] = GFC_DESCRIPTOR_STRIDE(x,n);
590 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(x,n);
591 1.1 mrg if (extent[n] <= 0)
592 1.1 mrg return;
593 1.1 mrg }
594 1.1 mrg
595 1.1 mrg stride0 = stride[0];
596 1.1 mrg
597 1.1 mrg if (unlikely (!rs->init))
598 1.1 mrg init_rand_state (rs, false);
599 1.1 mrg
600 1.1 mrg while (dest)
601 1.1 mrg {
602 1.1 mrg /* random_r8 (dest); */
603 1.1.1.2 mrg uint64_t r = prng_next (rs);
604 1.1 mrg rnumber_8 (dest, r);
605 1.1 mrg
606 1.1 mrg /* Advance to the next element. */
607 1.1 mrg dest += stride0;
608 1.1 mrg count[0]++;
609 1.1 mrg /* Advance to the next source element. */
610 1.1 mrg index_type n = 0;
611 1.1 mrg while (count[n] == extent[n])
612 1.1 mrg {
613 1.1 mrg /* When we get to the end of a dimension, reset it and increment
614 1.1 mrg the next dimension. */
615 1.1 mrg count[n] = 0;
616 1.1 mrg /* We could precalculate these products, but this is a less
617 1.1 mrg frequently used path so probably not worth it. */
618 1.1 mrg dest -= stride[n] * extent[n];
619 1.1 mrg n++;
620 1.1 mrg if (n == dim)
621 1.1 mrg {
622 1.1 mrg dest = NULL;
623 1.1 mrg break;
624 1.1 mrg }
625 1.1 mrg else
626 1.1 mrg {
627 1.1 mrg count[n]++;
628 1.1 mrg dest += stride[n];
629 1.1 mrg }
630 1.1 mrg }
631 1.1 mrg }
632 1.1 mrg }
633 1.1 mrg
634 1.1 mrg #ifdef HAVE_GFC_REAL_10
635 1.1 mrg
636 1.1 mrg /* This function fills a REAL(10) array with values from the uniform
637 1.1 mrg distribution with range [0,1). */
638 1.1 mrg
639 1.1 mrg void
640 1.1 mrg arandom_r10 (gfc_array_r10 *x)
641 1.1 mrg {
642 1.1 mrg index_type count[GFC_MAX_DIMENSIONS];
643 1.1 mrg index_type extent[GFC_MAX_DIMENSIONS];
644 1.1 mrg index_type stride[GFC_MAX_DIMENSIONS];
645 1.1 mrg index_type stride0;
646 1.1 mrg index_type dim;
647 1.1 mrg GFC_REAL_10 *dest;
648 1.1.1.2 mrg prng_state* rs = get_rand_state();
649 1.1 mrg
650 1.1 mrg dest = x->base_addr;
651 1.1 mrg
652 1.1 mrg dim = GFC_DESCRIPTOR_RANK (x);
653 1.1 mrg
654 1.1 mrg for (index_type n = 0; n < dim; n++)
655 1.1 mrg {
656 1.1 mrg count[n] = 0;
657 1.1 mrg stride[n] = GFC_DESCRIPTOR_STRIDE(x,n);
658 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(x,n);
659 1.1 mrg if (extent[n] <= 0)
660 1.1 mrg return;
661 1.1 mrg }
662 1.1 mrg
663 1.1 mrg stride0 = stride[0];
664 1.1 mrg
665 1.1 mrg if (unlikely (!rs->init))
666 1.1 mrg init_rand_state (rs, false);
667 1.1 mrg
668 1.1 mrg while (dest)
669 1.1 mrg {
670 1.1 mrg /* random_r10 (dest); */
671 1.1.1.2 mrg uint64_t r = prng_next (rs);
672 1.1 mrg rnumber_10 (dest, r);
673 1.1 mrg
674 1.1 mrg /* Advance to the next element. */
675 1.1 mrg dest += stride0;
676 1.1 mrg count[0]++;
677 1.1 mrg /* Advance to the next source element. */
678 1.1 mrg index_type n = 0;
679 1.1 mrg while (count[n] == extent[n])
680 1.1 mrg {
681 1.1 mrg /* When we get to the end of a dimension, reset it and increment
682 1.1 mrg the next dimension. */
683 1.1 mrg count[n] = 0;
684 1.1 mrg /* We could precalculate these products, but this is a less
685 1.1 mrg frequently used path so probably not worth it. */
686 1.1 mrg dest -= stride[n] * extent[n];
687 1.1 mrg n++;
688 1.1 mrg if (n == dim)
689 1.1 mrg {
690 1.1 mrg dest = NULL;
691 1.1 mrg break;
692 1.1 mrg }
693 1.1 mrg else
694 1.1 mrg {
695 1.1 mrg count[n]++;
696 1.1 mrg dest += stride[n];
697 1.1 mrg }
698 1.1 mrg }
699 1.1 mrg }
700 1.1 mrg }
701 1.1 mrg
702 1.1 mrg #endif
703 1.1 mrg
704 1.1 mrg #ifdef HAVE_GFC_REAL_16
705 1.1 mrg
706 1.1 mrg /* This function fills a REAL(16) array with values from the uniform
707 1.1 mrg distribution with range [0,1). */
708 1.1 mrg
709 1.1 mrg void
710 1.1 mrg arandom_r16 (gfc_array_r16 *x)
711 1.1 mrg {
712 1.1 mrg index_type count[GFC_MAX_DIMENSIONS];
713 1.1 mrg index_type extent[GFC_MAX_DIMENSIONS];
714 1.1 mrg index_type stride[GFC_MAX_DIMENSIONS];
715 1.1 mrg index_type stride0;
716 1.1 mrg index_type dim;
717 1.1 mrg GFC_REAL_16 *dest;
718 1.1.1.2 mrg prng_state* rs = get_rand_state();
719 1.1 mrg
720 1.1 mrg dest = x->base_addr;
721 1.1 mrg
722 1.1 mrg dim = GFC_DESCRIPTOR_RANK (x);
723 1.1 mrg
724 1.1 mrg for (index_type n = 0; n < dim; n++)
725 1.1 mrg {
726 1.1 mrg count[n] = 0;
727 1.1 mrg stride[n] = GFC_DESCRIPTOR_STRIDE(x,n);
728 1.1 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(x,n);
729 1.1 mrg if (extent[n] <= 0)
730 1.1 mrg return;
731 1.1 mrg }
732 1.1 mrg
733 1.1 mrg stride0 = stride[0];
734 1.1 mrg
735 1.1 mrg if (unlikely (!rs->init))
736 1.1 mrg init_rand_state (rs, false);
737 1.1 mrg
738 1.1 mrg while (dest)
739 1.1 mrg {
740 1.1 mrg /* random_r16 (dest); */
741 1.1.1.2 mrg uint64_t r1 = prng_next (rs);
742 1.1.1.2 mrg uint64_t r2 = prng_next (rs);
743 1.1 mrg rnumber_16 (dest, r1, r2);
744 1.1 mrg
745 1.1 mrg /* Advance to the next element. */
746 1.1 mrg dest += stride0;
747 1.1 mrg count[0]++;
748 1.1 mrg /* Advance to the next source element. */
749 1.1 mrg index_type n = 0;
750 1.1 mrg while (count[n] == extent[n])
751 1.1 mrg {
752 1.1 mrg /* When we get to the end of a dimension, reset it and increment
753 1.1 mrg the next dimension. */
754 1.1 mrg count[n] = 0;
755 1.1 mrg /* We could precalculate these products, but this is a less
756 1.1 mrg frequently used path so probably not worth it. */
757 1.1 mrg dest -= stride[n] * extent[n];
758 1.1 mrg n++;
759 1.1 mrg if (n == dim)
760 1.1 mrg {
761 1.1 mrg dest = NULL;
762 1.1 mrg break;
763 1.1 mrg }
764 1.1 mrg else
765 1.1 mrg {
766 1.1 mrg count[n]++;
767 1.1 mrg dest += stride[n];
768 1.1 mrg }
769 1.1 mrg }
770 1.1 mrg }
771 1.1 mrg }
772 1.1 mrg
773 1.1 mrg #endif
774 1.1 mrg
775 1.1.1.3 mrg #ifdef HAVE_GFC_REAL_17
776 1.1.1.3 mrg
777 1.1.1.3 mrg /* This function fills a REAL(16) array with values from the uniform
778 1.1.1.3 mrg distribution with range [0,1). */
779 1.1.1.3 mrg
780 1.1.1.3 mrg void
781 1.1.1.3 mrg arandom_r17 (gfc_array_r17 *x)
782 1.1.1.3 mrg {
783 1.1.1.3 mrg index_type count[GFC_MAX_DIMENSIONS];
784 1.1.1.3 mrg index_type extent[GFC_MAX_DIMENSIONS];
785 1.1.1.3 mrg index_type stride[GFC_MAX_DIMENSIONS];
786 1.1.1.3 mrg index_type stride0;
787 1.1.1.3 mrg index_type dim;
788 1.1.1.3 mrg GFC_REAL_17 *dest;
789 1.1.1.3 mrg prng_state* rs = get_rand_state();
790 1.1.1.3 mrg
791 1.1.1.3 mrg dest = x->base_addr;
792 1.1.1.3 mrg
793 1.1.1.3 mrg dim = GFC_DESCRIPTOR_RANK (x);
794 1.1.1.3 mrg
795 1.1.1.3 mrg for (index_type n = 0; n < dim; n++)
796 1.1.1.3 mrg {
797 1.1.1.3 mrg count[n] = 0;
798 1.1.1.3 mrg stride[n] = GFC_DESCRIPTOR_STRIDE(x,n);
799 1.1.1.3 mrg extent[n] = GFC_DESCRIPTOR_EXTENT(x,n);
800 1.1.1.3 mrg if (extent[n] <= 0)
801 1.1.1.3 mrg return;
802 1.1.1.3 mrg }
803 1.1.1.3 mrg
804 1.1.1.3 mrg stride0 = stride[0];
805 1.1.1.3 mrg
806 1.1.1.3 mrg if (unlikely (!rs->init))
807 1.1.1.3 mrg init_rand_state (rs, false);
808 1.1.1.3 mrg
809 1.1.1.3 mrg while (dest)
810 1.1.1.3 mrg {
811 1.1.1.3 mrg /* random_r17 (dest); */
812 1.1.1.3 mrg uint64_t r1 = prng_next (rs);
813 1.1.1.3 mrg uint64_t r2 = prng_next (rs);
814 1.1.1.3 mrg rnumber_17 (dest, r1, r2);
815 1.1.1.3 mrg
816 1.1.1.3 mrg /* Advance to the next element. */
817 1.1.1.3 mrg dest += stride0;
818 1.1.1.3 mrg count[0]++;
819 1.1.1.3 mrg /* Advance to the next source element. */
820 1.1.1.3 mrg index_type n = 0;
821 1.1.1.3 mrg while (count[n] == extent[n])
822 1.1.1.3 mrg {
823 1.1.1.3 mrg /* When we get to the end of a dimension, reset it and increment
824 1.1.1.3 mrg the next dimension. */
825 1.1.1.3 mrg count[n] = 0;
826 1.1.1.3 mrg /* We could precalculate these products, but this is a less
827 1.1.1.3 mrg frequently used path so probably not worth it. */
828 1.1.1.3 mrg dest -= stride[n] * extent[n];
829 1.1.1.3 mrg n++;
830 1.1.1.3 mrg if (n == dim)
831 1.1.1.3 mrg {
832 1.1.1.3 mrg dest = NULL;
833 1.1.1.3 mrg break;
834 1.1.1.3 mrg }
835 1.1.1.3 mrg else
836 1.1.1.3 mrg {
837 1.1.1.3 mrg count[n]++;
838 1.1.1.3 mrg dest += stride[n];
839 1.1.1.3 mrg }
840 1.1.1.3 mrg }
841 1.1.1.3 mrg }
842 1.1.1.3 mrg }
843 1.1.1.3 mrg
844 1.1.1.3 mrg #endif
845 1.1.1.3 mrg
846 1.1 mrg
847 1.1 mrg /* Number of elements in master_state array. */
848 1.1.1.2 mrg #define SZU64 (sizeof (master_state.s) / sizeof (uint64_t))
849 1.1 mrg
850 1.1.1.3 mrg /* Equivalent number of elements in an array of GFC_INTEGER_{4,8}. */
851 1.1.1.3 mrg #define SZ_IN_INT_4 (SZU64 * (sizeof (uint64_t) / sizeof (GFC_INTEGER_4)))
852 1.1.1.3 mrg #define SZ_IN_INT_8 (SZU64 * (sizeof (uint64_t) / sizeof (GFC_INTEGER_8)))
853 1.1 mrg
854 1.1 mrg /* Keys for scrambling the seed in order to avoid poor seeds. */
855 1.1 mrg
856 1.1 mrg static const uint64_t xor_keys[] = {
857 1.1 mrg 0xbd0c5b6e50c2df49ULL, 0xd46061cd46e1df38ULL, 0xbb4f4d4ed6103544ULL,
858 1.1.1.2 mrg 0x114a583d0756ad39ULL
859 1.1 mrg };
860 1.1 mrg
861 1.1 mrg
862 1.1 mrg /* Since a XOR cipher is symmetric, we need only one routine, and we
863 1.1 mrg can use it both for encryption and decryption. */
864 1.1 mrg
865 1.1 mrg static void
866 1.1 mrg scramble_seed (uint64_t *dest, const uint64_t *src)
867 1.1 mrg {
868 1.1 mrg for (size_t i = 0; i < SZU64; i++)
869 1.1 mrg dest[i] = src[i] ^ xor_keys[i];
870 1.1 mrg }
871 1.1 mrg
872 1.1 mrg
873 1.1 mrg /* random_seed is used to seed the PRNG with either a default
874 1.1 mrg set of seeds or user specified set of seeds. random_seed
875 1.1 mrg must be called with no argument or exactly one argument. */
876 1.1 mrg
877 1.1 mrg void
878 1.1 mrg random_seed_i4 (GFC_INTEGER_4 *size, gfc_array_i4 *put, gfc_array_i4 *get)
879 1.1 mrg {
880 1.1 mrg uint64_t seed[SZU64];
881 1.1 mrg
882 1.1 mrg /* Check that we only have one argument present. */
883 1.1 mrg if ((size ? 1 : 0) + (put ? 1 : 0) + (get ? 1 : 0) > 1)
884 1.1 mrg runtime_error ("RANDOM_SEED should have at most one argument present.");
885 1.1 mrg
886 1.1 mrg if (size != NULL)
887 1.1.1.3 mrg *size = SZ_IN_INT_4;
888 1.1 mrg
889 1.1.1.2 mrg prng_state* rs = get_rand_state();
890 1.1 mrg
891 1.1 mrg /* Return the seed to GET data. */
892 1.1 mrg if (get != NULL)
893 1.1 mrg {
894 1.1 mrg /* If the rank of the array is not 1, abort. */
895 1.1 mrg if (GFC_DESCRIPTOR_RANK (get) != 1)
896 1.1 mrg runtime_error ("Array rank of GET is not 1.");
897 1.1 mrg
898 1.1 mrg /* If the array is too small, abort. */
899 1.1.1.3 mrg if (GFC_DESCRIPTOR_EXTENT(get,0) < (index_type) SZ_IN_INT_4)
900 1.1 mrg runtime_error ("Array size of GET is too small.");
901 1.1 mrg
902 1.1 mrg if (!rs->init)
903 1.1 mrg init_rand_state (rs, false);
904 1.1 mrg
905 1.1 mrg /* Unscramble the seed. */
906 1.1 mrg scramble_seed (seed, rs->s);
907 1.1 mrg
908 1.1 mrg /* Then copy it back to the user variable. */
909 1.1.1.3 mrg for (size_t i = 0; i < SZ_IN_INT_4 ; i++)
910 1.1.1.3 mrg memcpy (&(get->base_addr[(SZ_IN_INT_4 - 1 - i) *
911 1.1.1.3 mrg GFC_DESCRIPTOR_STRIDE(get,0)]),
912 1.1 mrg (unsigned char*) seed + i * sizeof(GFC_UINTEGER_4),
913 1.1 mrg sizeof(GFC_UINTEGER_4));
914 1.1 mrg }
915 1.1 mrg
916 1.1 mrg else
917 1.1 mrg {
918 1.1 mrg __gthread_mutex_lock (&random_lock);
919 1.1 mrg
920 1.1 mrg /* From the standard: "If no argument is present, the processor assigns
921 1.1 mrg a processor-dependent value to the seed." */
922 1.1 mrg if (size == NULL && put == NULL && get == NULL)
923 1.1 mrg {
924 1.1.1.2 mrg master_state.init = false;
925 1.1 mrg init_rand_state (rs, true);
926 1.1 mrg }
927 1.1 mrg
928 1.1 mrg if (put != NULL)
929 1.1 mrg {
930 1.1 mrg /* If the rank of the array is not 1, abort. */
931 1.1 mrg if (GFC_DESCRIPTOR_RANK (put) != 1)
932 1.1 mrg runtime_error ("Array rank of PUT is not 1.");
933 1.1 mrg
934 1.1 mrg /* If the array is too small, abort. */
935 1.1.1.3 mrg if (GFC_DESCRIPTOR_EXTENT(put,0) < (index_type) SZ_IN_INT_4)
936 1.1 mrg runtime_error ("Array size of PUT is too small.");
937 1.1 mrg
938 1.1 mrg /* We copy the seed given by the user. */
939 1.1.1.3 mrg for (size_t i = 0; i < SZ_IN_INT_4; i++)
940 1.1 mrg memcpy ((unsigned char*) seed + i * sizeof(GFC_UINTEGER_4),
941 1.1.1.3 mrg &(put->base_addr[(SZ_IN_INT_4 - 1 - i) *
942 1.1.1.3 mrg GFC_DESCRIPTOR_STRIDE(put,0)]),
943 1.1 mrg sizeof(GFC_UINTEGER_4));
944 1.1 mrg
945 1.1 mrg /* We put it after scrambling the bytes, to paper around users who
946 1.1 mrg provide seeds with quality only in the lower or upper part. */
947 1.1.1.2 mrg scramble_seed (master_state.s, seed);
948 1.1.1.2 mrg master_state.init = true;
949 1.1 mrg init_rand_state (rs, true);
950 1.1 mrg }
951 1.1 mrg
952 1.1 mrg __gthread_mutex_unlock (&random_lock);
953 1.1 mrg }
954 1.1 mrg }
955 1.1 mrg iexport(random_seed_i4);
956 1.1 mrg
957 1.1 mrg
958 1.1 mrg void
959 1.1 mrg random_seed_i8 (GFC_INTEGER_8 *size, gfc_array_i8 *put, gfc_array_i8 *get)
960 1.1 mrg {
961 1.1 mrg uint64_t seed[SZU64];
962 1.1 mrg
963 1.1 mrg /* Check that we only have one argument present. */
964 1.1 mrg if ((size ? 1 : 0) + (put ? 1 : 0) + (get ? 1 : 0) > 1)
965 1.1 mrg runtime_error ("RANDOM_SEED should have at most one argument present.");
966 1.1 mrg
967 1.1 mrg if (size != NULL)
968 1.1.1.3 mrg *size = SZ_IN_INT_8;
969 1.1 mrg
970 1.1.1.2 mrg prng_state* rs = get_rand_state();
971 1.1 mrg
972 1.1 mrg /* Return the seed to GET data. */
973 1.1 mrg if (get != NULL)
974 1.1 mrg {
975 1.1 mrg /* If the rank of the array is not 1, abort. */
976 1.1 mrg if (GFC_DESCRIPTOR_RANK (get) != 1)
977 1.1 mrg runtime_error ("Array rank of GET is not 1.");
978 1.1 mrg
979 1.1 mrg /* If the array is too small, abort. */
980 1.1.1.3 mrg if (GFC_DESCRIPTOR_EXTENT(get,0) < (index_type) SZ_IN_INT_8)
981 1.1 mrg runtime_error ("Array size of GET is too small.");
982 1.1 mrg
983 1.1 mrg if (!rs->init)
984 1.1 mrg init_rand_state (rs, false);
985 1.1 mrg
986 1.1 mrg /* Unscramble the seed. */
987 1.1 mrg scramble_seed (seed, rs->s);
988 1.1 mrg
989 1.1 mrg /* This code now should do correct strides. */
990 1.1.1.3 mrg for (size_t i = 0; i < SZ_IN_INT_8; i++)
991 1.1 mrg memcpy (&(get->base_addr[i * GFC_DESCRIPTOR_STRIDE(get,0)]), &seed[i],
992 1.1 mrg sizeof (GFC_UINTEGER_8));
993 1.1 mrg }
994 1.1 mrg
995 1.1 mrg else
996 1.1 mrg {
997 1.1 mrg __gthread_mutex_lock (&random_lock);
998 1.1 mrg
999 1.1 mrg /* From the standard: "If no argument is present, the processor assigns
1000 1.1 mrg a processor-dependent value to the seed." */
1001 1.1 mrg if (size == NULL && put == NULL && get == NULL)
1002 1.1 mrg {
1003 1.1.1.2 mrg master_state.init = false;
1004 1.1 mrg init_rand_state (rs, true);
1005 1.1 mrg }
1006 1.1 mrg
1007 1.1 mrg if (put != NULL)
1008 1.1 mrg {
1009 1.1 mrg /* If the rank of the array is not 1, abort. */
1010 1.1 mrg if (GFC_DESCRIPTOR_RANK (put) != 1)
1011 1.1 mrg runtime_error ("Array rank of PUT is not 1.");
1012 1.1 mrg
1013 1.1 mrg /* If the array is too small, abort. */
1014 1.1.1.3 mrg if (GFC_DESCRIPTOR_EXTENT(put,0) < (index_type) SZ_IN_INT_8)
1015 1.1 mrg runtime_error ("Array size of PUT is too small.");
1016 1.1 mrg
1017 1.1 mrg /* This code now should do correct strides. */
1018 1.1.1.3 mrg for (size_t i = 0; i < SZ_IN_INT_8; i++)
1019 1.1 mrg memcpy (&seed[i], &(put->base_addr[i * GFC_DESCRIPTOR_STRIDE(put,0)]),
1020 1.1 mrg sizeof (GFC_UINTEGER_8));
1021 1.1 mrg
1022 1.1.1.2 mrg scramble_seed (master_state.s, seed);
1023 1.1.1.2 mrg master_state.init = true;
1024 1.1 mrg init_rand_state (rs, true);
1025 1.1 mrg }
1026 1.1 mrg
1027 1.1 mrg
1028 1.1 mrg __gthread_mutex_unlock (&random_lock);
1029 1.1 mrg }
1030 1.1 mrg }
1031 1.1 mrg iexport(random_seed_i8);
1032 1.1 mrg
1033 1.1 mrg
1034 1.1 mrg #if !defined __GTHREAD_MUTEX_INIT || defined __GTHREADS
1035 1.1 mrg static void __attribute__((constructor))
1036 1.1 mrg constructor_random (void)
1037 1.1 mrg {
1038 1.1 mrg #ifndef __GTHREAD_MUTEX_INIT
1039 1.1 mrg __GTHREAD_MUTEX_INIT_FUNCTION (&random_lock);
1040 1.1 mrg #endif
1041 1.1 mrg if (__gthread_active_p ())
1042 1.1 mrg __gthread_key_create (&rand_state_key, &free);
1043 1.1 mrg }
1044 1.1 mrg #endif
1045 1.1 mrg
1046 1.1 mrg #ifdef __GTHREADS
1047 1.1 mrg static void __attribute__((destructor))
1048 1.1 mrg destructor_random (void)
1049 1.1 mrg {
1050 1.1 mrg if (__gthread_active_p ())
1051 1.1 mrg __gthread_key_delete (rand_state_key);
1052 1.1 mrg }
1053 1.1 mrg #endif
1054