Home | History | Annotate | Line # | Download | only in intrinsics
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