1 /* Implementation of the RANDOM intrinsics
2 Copyright (C) 2002-2024 Free Software Foundation, Inc.
3 Contributed by Lars Segerlund <seger@linuxmail.org>,
4 Steve Kargl and Janne Blomqvist.
6 This file is part of the GNU Fortran runtime library (libgfortran).
8 Libgfortran is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public
10 License as published by the Free Software Foundation; either
11 version 3 of the License, or (at your option) any later version.
13 Ligbfortran is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 Under Section 7 of GPL version 3, you are granted additional
19 permissions described in the GCC Runtime Library Exception, version
20 3.1, as published by the Free Software Foundation.
22 You should have received a copy of the GNU General Public License and
23 a copy of the GCC Runtime Library Exception along with this program;
24 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 <http://www.gnu.org/licenses/>. */
30 #include "libgfortran.h"
40 #ifdef HAVE_SYS_RANDOM_H
41 #include <sys/random.h>
47 #include <_mingw.h> /* For __MINGW64_VERSION_MAJOR */
50 extern void random_r4 (GFC_REAL_4
*);
51 iexport_proto(random_r4
);
53 extern void random_r8 (GFC_REAL_8
*);
54 iexport_proto(random_r8
);
56 extern void arandom_r4 (gfc_array_r4
*);
57 export_proto(arandom_r4
);
59 extern void arandom_r8 (gfc_array_r8
*);
60 export_proto(arandom_r8
);
62 #ifdef HAVE_GFC_REAL_10
64 extern void random_r10 (GFC_REAL_10
*);
65 iexport_proto(random_r10
);
67 extern void arandom_r10 (gfc_array_r10
*);
68 export_proto(arandom_r10
);
72 #ifdef HAVE_GFC_REAL_16
74 extern void random_r16 (GFC_REAL_16
*);
75 iexport_proto(random_r16
);
77 extern void arandom_r16 (gfc_array_r16
*);
78 export_proto(arandom_r16
);
82 #ifdef HAVE_GFC_REAL_17
84 extern void random_r17 (GFC_REAL_17
*);
85 iexport_proto(random_r17
);
87 extern void arandom_r17 (gfc_array_r17
*);
88 export_proto(arandom_r17
);
92 #ifdef __GTHREAD_MUTEX_INIT
93 static __gthread_mutex_t random_lock
= __GTHREAD_MUTEX_INIT
;
95 static __gthread_mutex_t random_lock
;
98 /* Helper routines to map a GFC_UINTEGER_* to the corresponding
99 GFC_REAL_* types in the range of [0,1). If GFC_REAL_*_RADIX are 2
100 or 16, respectively, we mask off the bits that don't fit into the
101 correct GFC_REAL_*, convert to the real type, then multiply by the
106 rnumber_4 (GFC_REAL_4
*f
, GFC_UINTEGER_4 v
)
109 #if GFC_REAL_4_RADIX == 2
110 mask
= ~ (GFC_UINTEGER_4
) 0u << (32 - GFC_REAL_4_DIGITS
);
111 #elif GFC_REAL_4_RADIX == 16
112 mask
= ~ (GFC_UINTEGER_4
) 0u << ((8 - GFC_REAL_4_DIGITS
) * 4);
114 #error "GFC_REAL_4_RADIX has unknown value"
117 *f
= (GFC_REAL_4
) v
* GFC_REAL_4_LITERAL(0x1.p
-32);
121 rnumber_8 (GFC_REAL_8
*f
, GFC_UINTEGER_8 v
)
124 #if GFC_REAL_8_RADIX == 2
125 mask
= ~ (GFC_UINTEGER_8
) 0u << (64 - GFC_REAL_8_DIGITS
);
126 #elif GFC_REAL_8_RADIX == 16
127 mask
= ~ (GFC_UINTEGER_8
) 0u << (16 - GFC_REAL_8_DIGITS
) * 4);
129 #error "GFC_REAL_8_RADIX has unknown value"
132 *f
= (GFC_REAL_8
) v
* GFC_REAL_8_LITERAL(0x1.p
-64);
135 #ifdef HAVE_GFC_REAL_10
138 rnumber_10 (GFC_REAL_10
*f
, GFC_UINTEGER_8 v
)
141 #if GFC_REAL_10_RADIX == 2
142 mask
= ~ (GFC_UINTEGER_8
) 0u << (64 - GFC_REAL_10_DIGITS
);
143 #elif GFC_REAL_10_RADIX == 16
144 mask
= ~ (GFC_UINTEGER_10
) 0u << ((16 - GFC_REAL_10_DIGITS
) * 4);
146 #error "GFC_REAL_10_RADIX has unknown value"
149 *f
= (GFC_REAL_10
) v
* GFC_REAL_10_LITERAL(0x1.p
-64);
153 #ifdef HAVE_GFC_REAL_16
155 /* For REAL(KIND=16), we only need to mask off the lower bits. */
158 rnumber_16 (GFC_REAL_16
*f
, GFC_UINTEGER_8 v1
, GFC_UINTEGER_8 v2
)
161 #if GFC_REAL_16_RADIX == 2
162 mask
= ~ (GFC_UINTEGER_8
) 0u << (128 - GFC_REAL_16_DIGITS
);
163 #elif GFC_REAL_16_RADIX == 16
164 mask
= ~ (GFC_UINTEGER_8
) 0u << ((32 - GFC_REAL_16_DIGITS
) * 4);
166 #error "GFC_REAL_16_RADIX has unknown value"
169 *f
= (GFC_REAL_16
) v1
* GFC_REAL_16_LITERAL(0x1.p
-64)
170 + (GFC_REAL_16
) v2
* GFC_REAL_16_LITERAL(0x1.p
-128);
174 #ifdef HAVE_GFC_REAL_17
176 /* For REAL(KIND=16), we only need to mask off the lower bits. */
179 rnumber_17 (GFC_REAL_17
*f
, GFC_UINTEGER_8 v1
, GFC_UINTEGER_8 v2
)
182 #if GFC_REAL_17_RADIX == 2
183 mask
= ~ (GFC_UINTEGER_8
) 0u << (128 - GFC_REAL_17_DIGITS
);
184 #elif GFC_REAL_17_RADIX == 16
185 mask
= ~ (GFC_UINTEGER_8
) 0u << ((32 - GFC_REAL_17_DIGITS
) * 4);
187 #error "GFC_REAL_17_RADIX has unknown value"
190 *f
= (GFC_REAL_17
) v1
* GFC_REAL_17_LITERAL(0x1.p
-64)
191 + (GFC_REAL_17
) v2
* GFC_REAL_17_LITERAL(0x1.p
-128);
198 We use the xoshiro256** generator, a fast high-quality generator
201 - passes TestU1 without any failures
203 - provides a "jump" function making it easy to provide many
204 independent parallel streams.
206 - Long period of 2**256 - 1
208 A description can be found at
210 http://prng.di.unimi.it/
214 https://arxiv.org/abs/1805.01407
216 The paper includes public domain source code which is the basis for
217 the implementation below.
228 /* master_state is the only variable protected by random_lock. */
229 static prng_state master_state
= { .init
= false, .s
= {
230 0xad63fa1ed3b55f36ULL
, 0xd94473e78978b497ULL
, 0xbc60592a98172477ULL
,
231 0xa3de7c6e81265301ULL
}
235 static __gthread_key_t rand_state_key
;
238 get_rand_state (void)
240 /* For single threaded apps. */
241 static prng_state rand_state
;
243 if (__gthread_active_p ())
245 void* p
= __gthread_getspecific (rand_state_key
);
248 p
= xcalloc (1, sizeof (prng_state
));
249 __gthread_setspecific (rand_state_key
, p
);
257 static inline uint64_t
258 rotl (const uint64_t x
, int k
)
260 return (x
<< k
) | (x
>> (64 - k
));
265 prng_next (prng_state
* rs
)
267 const uint64_t result
= rotl(rs
->s
[1] * 5, 7) * 9;
269 const uint64_t t
= rs
->s
[1] << 17;
271 rs
->s
[2] ^= rs
->s
[0];
272 rs
->s
[3] ^= rs
->s
[1];
273 rs
->s
[1] ^= rs
->s
[2];
274 rs
->s
[0] ^= rs
->s
[3];
278 rs
->s
[3] = rotl(rs
->s
[3], 45);
284 /* This is the jump function for the generator. It is equivalent to
285 2^128 calls to prng_next(); it can be used to generate 2^128
286 non-overlapping subsequences for parallel computations. */
289 jump (prng_state
* rs
)
291 static const uint64_t JUMP
[] = { 0x180ec6d33cfd0aba, 0xd5a61266f0c9392c, 0xa9582618e03fc9aa, 0x39abdc4529b1661c };
297 for(size_t i
= 0; i
< sizeof JUMP
/ sizeof *JUMP
; i
++)
298 for(int b
= 0; b
< 64; b
++) {
299 if (JUMP
[i
] & UINT64_C(1) << b
) {
315 /* Splitmix64 recommended by xoshiro author for initializing. After
316 getting one uint64_t value from the OS, this is used to fill in the
317 rest of the xoshiro state. */
320 splitmix64 (uint64_t x
)
322 uint64_t z
= (x
+= 0x9e3779b97f4a7c15);
323 z
= (z
^ (z
>> 30)) * 0xbf58476d1ce4e5b9;
324 z
= (z
^ (z
>> 27)) * 0x94d049bb133111eb;
325 return z
^ (z
>> 31);
329 /* Get some bytes from the operating system in order to seed
333 getosrandom (void *buf
, size_t buflen
)
335 /* rand_s is available in MinGW-w64 but not plain MinGW. */
336 #if defined(__MINGW64_VERSION_MAJOR)
337 unsigned int* b
= buf
;
338 for (size_t i
= 0; i
< buflen
/ sizeof (unsigned int); i
++)
342 #ifdef HAVE_GETENTROPY
343 if (getentropy (buf
, buflen
) == 0)
346 int flags
= O_RDONLY
;
350 int fd
= open("/dev/urandom", flags
);
353 int res
= read(fd
, buf
, buflen
);
357 uint64_t seed
= 0x047f7684e9fc949dULL
;
360 if (gf_gettime (&secs
, &usecs
) == 0)
366 pid_t pid
= getpid();
369 size_t size
= buflen
< sizeof (uint64_t) ? buflen
: sizeof (uint64_t);
370 memcpy (buf
, &seed
, size
);
372 #endif /* __MINGW64_VERSION_MAJOR */
376 /* Initialize the random number generator for the current thread,
377 using the master state and the number of times we must jump. */
380 init_rand_state (prng_state
* rs
, const bool locked
)
383 __gthread_mutex_lock (&random_lock
);
384 if (!master_state
.init
)
387 getosrandom (&os_seed
, sizeof (os_seed
));
388 for (uint64_t i
= 0; i
< sizeof (master_state
.s
) / sizeof (uint64_t); i
++)
390 os_seed
= splitmix64 (os_seed
);
391 master_state
.s
[i
] = os_seed
;
393 master_state
.init
= true;
395 memcpy (&rs
->s
, master_state
.s
, sizeof (master_state
.s
));
396 jump (&master_state
);
398 __gthread_mutex_unlock (&random_lock
);
403 /* This function produces a REAL(4) value from the uniform distribution
407 random_r4 (GFC_REAL_4
*x
)
409 prng_state
* rs
= get_rand_state();
411 if (unlikely (!rs
->init
))
412 init_rand_state (rs
, false);
413 uint64_t r
= prng_next (rs
);
414 /* Take the higher bits, ensuring that a stream of real(4), real(8),
415 and real(10) will be identical (except for precision). */
416 uint32_t high
= (uint32_t) (r
>> 32);
421 /* This function produces a REAL(8) value from the uniform distribution
425 random_r8 (GFC_REAL_8
*x
)
428 prng_state
* rs
= get_rand_state();
430 if (unlikely (!rs
->init
))
431 init_rand_state (rs
, false);
437 #ifdef HAVE_GFC_REAL_10
439 /* This function produces a REAL(10) value from the uniform distribution
443 random_r10 (GFC_REAL_10
*x
)
446 prng_state
* rs
= get_rand_state();
448 if (unlikely (!rs
->init
))
449 init_rand_state (rs
, false);
457 /* This function produces a REAL(16) value from the uniform distribution
460 #ifdef HAVE_GFC_REAL_16
463 random_r16 (GFC_REAL_16
*x
)
465 GFC_UINTEGER_8 r1
, r2
;
466 prng_state
* rs
= get_rand_state();
468 if (unlikely (!rs
->init
))
469 init_rand_state (rs
, false);
472 rnumber_16 (x
, r1
, r2
);
479 /* This function produces a REAL(16) value from the uniform distribution
482 #ifdef HAVE_GFC_REAL_17
485 random_r17 (GFC_REAL_17
*x
)
487 GFC_UINTEGER_8 r1
, r2
;
488 prng_state
* rs
= get_rand_state();
490 if (unlikely (!rs
->init
))
491 init_rand_state (rs
, false);
494 rnumber_17 (x
, r1
, r2
);
501 /* This function fills a REAL(4) array with values from the uniform
502 distribution with range [0,1). */
505 arandom_r4 (gfc_array_r4
*x
)
507 index_type count
[GFC_MAX_DIMENSIONS
];
508 index_type extent
[GFC_MAX_DIMENSIONS
];
509 index_type stride
[GFC_MAX_DIMENSIONS
];
513 prng_state
* rs
= get_rand_state();
517 dim
= GFC_DESCRIPTOR_RANK (x
);
519 for (index_type n
= 0; n
< dim
; n
++)
522 stride
[n
] = GFC_DESCRIPTOR_STRIDE(x
,n
);
523 extent
[n
] = GFC_DESCRIPTOR_EXTENT(x
,n
);
530 if (unlikely (!rs
->init
))
531 init_rand_state (rs
, false);
535 /* random_r4 (dest); */
536 uint64_t r
= prng_next (rs
);
537 uint32_t high
= (uint32_t) (r
>> 32);
538 rnumber_4 (dest
, high
);
540 /* Advance to the next element. */
543 /* Advance to the next source element. */
545 while (count
[n
] == extent
[n
])
547 /* When we get to the end of a dimension, reset it and increment
548 the next dimension. */
550 /* We could precalculate these products, but this is a less
551 frequently used path so probably not worth it. */
552 dest
-= stride
[n
] * extent
[n
];
568 /* This function fills a REAL(8) array with values from the uniform
569 distribution with range [0,1). */
572 arandom_r8 (gfc_array_r8
*x
)
574 index_type count
[GFC_MAX_DIMENSIONS
];
575 index_type extent
[GFC_MAX_DIMENSIONS
];
576 index_type stride
[GFC_MAX_DIMENSIONS
];
580 prng_state
* rs
= get_rand_state();
584 dim
= GFC_DESCRIPTOR_RANK (x
);
586 for (index_type n
= 0; n
< dim
; n
++)
589 stride
[n
] = GFC_DESCRIPTOR_STRIDE(x
,n
);
590 extent
[n
] = GFC_DESCRIPTOR_EXTENT(x
,n
);
597 if (unlikely (!rs
->init
))
598 init_rand_state (rs
, false);
602 /* random_r8 (dest); */
603 uint64_t r
= prng_next (rs
);
606 /* Advance to the next element. */
609 /* Advance to the next source element. */
611 while (count
[n
] == extent
[n
])
613 /* When we get to the end of a dimension, reset it and increment
614 the next dimension. */
616 /* We could precalculate these products, but this is a less
617 frequently used path so probably not worth it. */
618 dest
-= stride
[n
] * extent
[n
];
634 #ifdef HAVE_GFC_REAL_10
636 /* This function fills a REAL(10) array with values from the uniform
637 distribution with range [0,1). */
640 arandom_r10 (gfc_array_r10
*x
)
642 index_type count
[GFC_MAX_DIMENSIONS
];
643 index_type extent
[GFC_MAX_DIMENSIONS
];
644 index_type stride
[GFC_MAX_DIMENSIONS
];
648 prng_state
* rs
= get_rand_state();
652 dim
= GFC_DESCRIPTOR_RANK (x
);
654 for (index_type n
= 0; n
< dim
; n
++)
657 stride
[n
] = GFC_DESCRIPTOR_STRIDE(x
,n
);
658 extent
[n
] = GFC_DESCRIPTOR_EXTENT(x
,n
);
665 if (unlikely (!rs
->init
))
666 init_rand_state (rs
, false);
670 /* random_r10 (dest); */
671 uint64_t r
= prng_next (rs
);
672 rnumber_10 (dest
, r
);
674 /* Advance to the next element. */
677 /* Advance to the next source element. */
679 while (count
[n
] == extent
[n
])
681 /* When we get to the end of a dimension, reset it and increment
682 the next dimension. */
684 /* We could precalculate these products, but this is a less
685 frequently used path so probably not worth it. */
686 dest
-= stride
[n
] * extent
[n
];
704 #ifdef HAVE_GFC_REAL_16
706 /* This function fills a REAL(16) array with values from the uniform
707 distribution with range [0,1). */
710 arandom_r16 (gfc_array_r16
*x
)
712 index_type count
[GFC_MAX_DIMENSIONS
];
713 index_type extent
[GFC_MAX_DIMENSIONS
];
714 index_type stride
[GFC_MAX_DIMENSIONS
];
718 prng_state
* rs
= get_rand_state();
722 dim
= GFC_DESCRIPTOR_RANK (x
);
724 for (index_type n
= 0; n
< dim
; n
++)
727 stride
[n
] = GFC_DESCRIPTOR_STRIDE(x
,n
);
728 extent
[n
] = GFC_DESCRIPTOR_EXTENT(x
,n
);
735 if (unlikely (!rs
->init
))
736 init_rand_state (rs
, false);
740 /* random_r16 (dest); */
741 uint64_t r1
= prng_next (rs
);
742 uint64_t r2
= prng_next (rs
);
743 rnumber_16 (dest
, r1
, r2
);
745 /* Advance to the next element. */
748 /* Advance to the next source element. */
750 while (count
[n
] == extent
[n
])
752 /* When we get to the end of a dimension, reset it and increment
753 the next dimension. */
755 /* We could precalculate these products, but this is a less
756 frequently used path so probably not worth it. */
757 dest
-= stride
[n
] * extent
[n
];
775 #ifdef HAVE_GFC_REAL_17
777 /* This function fills a REAL(16) array with values from the uniform
778 distribution with range [0,1). */
781 arandom_r17 (gfc_array_r17
*x
)
783 index_type count
[GFC_MAX_DIMENSIONS
];
784 index_type extent
[GFC_MAX_DIMENSIONS
];
785 index_type stride
[GFC_MAX_DIMENSIONS
];
789 prng_state
* rs
= get_rand_state();
793 dim
= GFC_DESCRIPTOR_RANK (x
);
795 for (index_type n
= 0; n
< dim
; n
++)
798 stride
[n
] = GFC_DESCRIPTOR_STRIDE(x
,n
);
799 extent
[n
] = GFC_DESCRIPTOR_EXTENT(x
,n
);
806 if (unlikely (!rs
->init
))
807 init_rand_state (rs
, false);
811 /* random_r17 (dest); */
812 uint64_t r1
= prng_next (rs
);
813 uint64_t r2
= prng_next (rs
);
814 rnumber_17 (dest
, r1
, r2
);
816 /* Advance to the next element. */
819 /* Advance to the next source element. */
821 while (count
[n
] == extent
[n
])
823 /* When we get to the end of a dimension, reset it and increment
824 the next dimension. */
826 /* We could precalculate these products, but this is a less
827 frequently used path so probably not worth it. */
828 dest
-= stride
[n
] * extent
[n
];
847 /* Number of elements in master_state array. */
848 #define SZU64 (sizeof (master_state.s) / sizeof (uint64_t))
850 /* Equivalent number of elements in an array of GFC_INTEGER_{4,8}. */
851 #define SZ_IN_INT_4 (SZU64 * (sizeof (uint64_t) / sizeof (GFC_INTEGER_4)))
852 #define SZ_IN_INT_8 (SZU64 * (sizeof (uint64_t) / sizeof (GFC_INTEGER_8)))
854 /* Keys for scrambling the seed in order to avoid poor seeds. */
856 static const uint64_t xor_keys
[] = {
857 0xbd0c5b6e50c2df49ULL
, 0xd46061cd46e1df38ULL
, 0xbb4f4d4ed6103544ULL
,
858 0x114a583d0756ad39ULL
862 /* Since a XOR cipher is symmetric, we need only one routine, and we
863 can use it both for encryption and decryption. */
866 scramble_seed (uint64_t *dest
, const uint64_t *src
)
868 for (size_t i
= 0; i
< SZU64
; i
++)
869 dest
[i
] = src
[i
] ^ xor_keys
[i
];
873 /* random_seed is used to seed the PRNG with either a default
874 set of seeds or user specified set of seeds. random_seed
875 must be called with no argument or exactly one argument. */
878 random_seed_i4 (GFC_INTEGER_4
*size
, gfc_array_i4
*put
, gfc_array_i4
*get
)
880 uint64_t seed
[SZU64
];
882 /* Check that we only have one argument present. */
883 if ((size
? 1 : 0) + (put
? 1 : 0) + (get
? 1 : 0) > 1)
884 runtime_error ("RANDOM_SEED should have at most one argument present.");
889 prng_state
* rs
= get_rand_state();
891 /* Return the seed to GET data. */
894 /* If the rank of the array is not 1, abort. */
895 if (GFC_DESCRIPTOR_RANK (get
) != 1)
896 runtime_error ("Array rank of GET is not 1.");
898 /* If the array is too small, abort. */
899 if (GFC_DESCRIPTOR_EXTENT(get
,0) < (index_type
) SZ_IN_INT_4
)
900 runtime_error ("Array size of GET is too small.");
903 init_rand_state (rs
, false);
905 /* Unscramble the seed. */
906 scramble_seed (seed
, rs
->s
);
908 /* Then copy it back to the user variable. */
909 for (size_t i
= 0; i
< SZ_IN_INT_4
; i
++)
910 memcpy (&(get
->base_addr
[(SZ_IN_INT_4
- 1 - i
) *
911 GFC_DESCRIPTOR_STRIDE(get
,0)]),
912 (unsigned char*) seed
+ i
* sizeof(GFC_UINTEGER_4
),
913 sizeof(GFC_UINTEGER_4
));
918 __gthread_mutex_lock (&random_lock
);
920 /* From the standard: "If no argument is present, the processor assigns
921 a processor-dependent value to the seed." */
922 if (size
== NULL
&& put
== NULL
&& get
== NULL
)
924 master_state
.init
= false;
925 init_rand_state (rs
, true);
930 /* If the rank of the array is not 1, abort. */
931 if (GFC_DESCRIPTOR_RANK (put
) != 1)
932 runtime_error ("Array rank of PUT is not 1.");
934 /* If the array is too small, abort. */
935 if (GFC_DESCRIPTOR_EXTENT(put
,0) < (index_type
) SZ_IN_INT_4
)
936 runtime_error ("Array size of PUT is too small.");
938 /* We copy the seed given by the user. */
939 for (size_t i
= 0; i
< SZ_IN_INT_4
; i
++)
940 memcpy ((unsigned char*) seed
+ i
* sizeof(GFC_UINTEGER_4
),
941 &(put
->base_addr
[(SZ_IN_INT_4
- 1 - i
) *
942 GFC_DESCRIPTOR_STRIDE(put
,0)]),
943 sizeof(GFC_UINTEGER_4
));
945 /* We put it after scrambling the bytes, to paper around users who
946 provide seeds with quality only in the lower or upper part. */
947 scramble_seed (master_state
.s
, seed
);
948 master_state
.init
= true;
949 init_rand_state (rs
, true);
952 __gthread_mutex_unlock (&random_lock
);
955 iexport(random_seed_i4
);
959 random_seed_i8 (GFC_INTEGER_8
*size
, gfc_array_i8
*put
, gfc_array_i8
*get
)
961 uint64_t seed
[SZU64
];
963 /* Check that we only have one argument present. */
964 if ((size
? 1 : 0) + (put
? 1 : 0) + (get
? 1 : 0) > 1)
965 runtime_error ("RANDOM_SEED should have at most one argument present.");
970 prng_state
* rs
= get_rand_state();
972 /* Return the seed to GET data. */
975 /* If the rank of the array is not 1, abort. */
976 if (GFC_DESCRIPTOR_RANK (get
) != 1)
977 runtime_error ("Array rank of GET is not 1.");
979 /* If the array is too small, abort. */
980 if (GFC_DESCRIPTOR_EXTENT(get
,0) < (index_type
) SZ_IN_INT_8
)
981 runtime_error ("Array size of GET is too small.");
984 init_rand_state (rs
, false);
986 /* Unscramble the seed. */
987 scramble_seed (seed
, rs
->s
);
989 /* This code now should do correct strides. */
990 for (size_t i
= 0; i
< SZ_IN_INT_8
; i
++)
991 memcpy (&(get
->base_addr
[i
* GFC_DESCRIPTOR_STRIDE(get
,0)]), &seed
[i
],
992 sizeof (GFC_UINTEGER_8
));
997 __gthread_mutex_lock (&random_lock
);
999 /* From the standard: "If no argument is present, the processor assigns
1000 a processor-dependent value to the seed." */
1001 if (size
== NULL
&& put
== NULL
&& get
== NULL
)
1003 master_state
.init
= false;
1004 init_rand_state (rs
, true);
1009 /* If the rank of the array is not 1, abort. */
1010 if (GFC_DESCRIPTOR_RANK (put
) != 1)
1011 runtime_error ("Array rank of PUT is not 1.");
1013 /* If the array is too small, abort. */
1014 if (GFC_DESCRIPTOR_EXTENT(put
,0) < (index_type
) SZ_IN_INT_8
)
1015 runtime_error ("Array size of PUT is too small.");
1017 /* This code now should do correct strides. */
1018 for (size_t i
= 0; i
< SZ_IN_INT_8
; i
++)
1019 memcpy (&seed
[i
], &(put
->base_addr
[i
* GFC_DESCRIPTOR_STRIDE(put
,0)]),
1020 sizeof (GFC_UINTEGER_8
));
1022 scramble_seed (master_state
.s
, seed
);
1023 master_state
.init
= true;
1024 init_rand_state (rs
, true);
1028 __gthread_mutex_unlock (&random_lock
);
1031 iexport(random_seed_i8
);
1034 #if !defined __GTHREAD_MUTEX_INIT || defined __GTHREADS
1035 static void __attribute__((constructor
))
1036 constructor_random (void)
1038 #ifndef __GTHREAD_MUTEX_INIT
1039 __GTHREAD_MUTEX_INIT_FUNCTION (&random_lock
);
1041 if (__gthread_active_p ())
1042 __gthread_key_create (&rand_state_key
, &free
);
1047 static void __attribute__((destructor
))
1048 destructor_random (void)
1050 if (__gthread_active_p ())
1051 __gthread_key_delete (rand_state_key
);