Home | History | Annotate | Line # | Download | only in intrinsics
random.c revision 1.1
      1  1.1  mrg /* Implementation of the RANDOM intrinsics
      2  1.1  mrg    Copyright (C) 2002-2019 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  mrg #ifdef __GTHREAD_MUTEX_INIT
     83  1.1  mrg static __gthread_mutex_t random_lock = __GTHREAD_MUTEX_INIT;
     84  1.1  mrg #else
     85  1.1  mrg static __gthread_mutex_t random_lock;
     86  1.1  mrg #endif
     87  1.1  mrg 
     88  1.1  mrg /* Helper routines to map a GFC_UINTEGER_* to the corresponding
     89  1.1  mrg    GFC_REAL_* types in the range of [0,1).  If GFC_REAL_*_RADIX are 2
     90  1.1  mrg    or 16, respectively, we mask off the bits that don't fit into the
     91  1.1  mrg    correct GFC_REAL_*, convert to the real type, then multiply by the
     92  1.1  mrg    correct offset.  */
     93  1.1  mrg 
     94  1.1  mrg 
     95  1.1  mrg static void
     96  1.1  mrg rnumber_4 (GFC_REAL_4 *f, GFC_UINTEGER_4 v)
     97  1.1  mrg {
     98  1.1  mrg   GFC_UINTEGER_4 mask;
     99  1.1  mrg #if GFC_REAL_4_RADIX == 2
    100  1.1  mrg   mask = ~ (GFC_UINTEGER_4) 0u << (32 - GFC_REAL_4_DIGITS);
    101  1.1  mrg #elif GFC_REAL_4_RADIX == 16
    102  1.1  mrg   mask = ~ (GFC_UINTEGER_4) 0u << ((8 - GFC_REAL_4_DIGITS) * 4);
    103  1.1  mrg #else
    104  1.1  mrg #error "GFC_REAL_4_RADIX has unknown value"
    105  1.1  mrg #endif
    106  1.1  mrg   v = v & mask;
    107  1.1  mrg   *f = (GFC_REAL_4) v * GFC_REAL_4_LITERAL(0x1.p-32);
    108  1.1  mrg }
    109  1.1  mrg 
    110  1.1  mrg static void
    111  1.1  mrg rnumber_8 (GFC_REAL_8 *f, GFC_UINTEGER_8 v)
    112  1.1  mrg {
    113  1.1  mrg   GFC_UINTEGER_8 mask;
    114  1.1  mrg #if GFC_REAL_8_RADIX == 2
    115  1.1  mrg   mask = ~ (GFC_UINTEGER_8) 0u << (64 - GFC_REAL_8_DIGITS);
    116  1.1  mrg #elif GFC_REAL_8_RADIX == 16
    117  1.1  mrg   mask = ~ (GFC_UINTEGER_8) 0u << (16 - GFC_REAL_8_DIGITS) * 4);
    118  1.1  mrg #else
    119  1.1  mrg #error "GFC_REAL_8_RADIX has unknown value"
    120  1.1  mrg #endif
    121  1.1  mrg   v = v & mask;
    122  1.1  mrg   *f = (GFC_REAL_8) v * GFC_REAL_8_LITERAL(0x1.p-64);
    123  1.1  mrg }
    124  1.1  mrg 
    125  1.1  mrg #ifdef HAVE_GFC_REAL_10
    126  1.1  mrg 
    127  1.1  mrg static void
    128  1.1  mrg rnumber_10 (GFC_REAL_10 *f, GFC_UINTEGER_8 v)
    129  1.1  mrg {
    130  1.1  mrg   GFC_UINTEGER_8 mask;
    131  1.1  mrg #if GFC_REAL_10_RADIX == 2
    132  1.1  mrg   mask = ~ (GFC_UINTEGER_8) 0u << (64 - GFC_REAL_10_DIGITS);
    133  1.1  mrg #elif GFC_REAL_10_RADIX == 16
    134  1.1  mrg   mask = ~ (GFC_UINTEGER_10) 0u << ((16 - GFC_REAL_10_DIGITS) * 4);
    135  1.1  mrg #else
    136  1.1  mrg #error "GFC_REAL_10_RADIX has unknown value"
    137  1.1  mrg #endif
    138  1.1  mrg   v = v & mask;
    139  1.1  mrg   *f = (GFC_REAL_10) v * GFC_REAL_10_LITERAL(0x1.p-64);
    140  1.1  mrg }
    141  1.1  mrg #endif
    142  1.1  mrg 
    143  1.1  mrg #ifdef HAVE_GFC_REAL_16
    144  1.1  mrg 
    145  1.1  mrg /* For REAL(KIND=16), we only need to mask off the lower bits.  */
    146  1.1  mrg 
    147  1.1  mrg static void
    148  1.1  mrg rnumber_16 (GFC_REAL_16 *f, GFC_UINTEGER_8 v1, GFC_UINTEGER_8 v2)
    149  1.1  mrg {
    150  1.1  mrg   GFC_UINTEGER_8 mask;
    151  1.1  mrg #if GFC_REAL_16_RADIX == 2
    152  1.1  mrg   mask = ~ (GFC_UINTEGER_8) 0u << (128 - GFC_REAL_16_DIGITS);
    153  1.1  mrg #elif GFC_REAL_16_RADIX == 16
    154  1.1  mrg   mask = ~ (GFC_UINTEGER_8) 0u << ((32 - GFC_REAL_16_DIGITS) * 4);
    155  1.1  mrg #else
    156  1.1  mrg #error "GFC_REAL_16_RADIX has unknown value"
    157  1.1  mrg #endif
    158  1.1  mrg   v2 = v2 & mask;
    159  1.1  mrg   *f = (GFC_REAL_16) v1 * GFC_REAL_16_LITERAL(0x1.p-64)
    160  1.1  mrg     + (GFC_REAL_16) v2 * GFC_REAL_16_LITERAL(0x1.p-128);
    161  1.1  mrg }
    162  1.1  mrg #endif
    163  1.1  mrg 
    164  1.1  mrg 
    165  1.1  mrg /*
    166  1.1  mrg 
    167  1.1  mrg    We use the xorshift1024* generator, a fast high-quality generator
    168  1.1  mrg    that:
    169  1.1  mrg 
    170  1.1  mrg    - passes TestU1 without any failures
    171  1.1  mrg 
    172  1.1  mrg    - provides a "jump" function making it easy to provide many
    173  1.1  mrg      independent parallel streams.
    174  1.1  mrg 
    175  1.1  mrg    - Long period of 2**1024 - 1
    176  1.1  mrg 
    177  1.1  mrg    A description can be found at
    178  1.1  mrg 
    179  1.1  mrg    http://vigna.di.unimi.it/ftp/papers/xorshift.pdf
    180  1.1  mrg 
    181  1.1  mrg    or
    182  1.1  mrg 
    183  1.1  mrg    http://arxiv.org/abs/1402.6246
    184  1.1  mrg 
    185  1.1  mrg    The paper includes public domain source code which is the basis for
    186  1.1  mrg    the implementation below.
    187  1.1  mrg 
    188  1.1  mrg */
    189  1.1  mrg typedef struct
    190  1.1  mrg {
    191  1.1  mrg   bool init;
    192  1.1  mrg   int p;
    193  1.1  mrg   uint64_t s[16];
    194  1.1  mrg }
    195  1.1  mrg xorshift1024star_state;
    196  1.1  mrg 
    197  1.1  mrg 
    198  1.1  mrg /* master_init, njumps, and master_state are the only variables
    199  1.1  mrg    protected by random_lock.  */
    200  1.1  mrg static bool master_init;
    201  1.1  mrg static unsigned njumps; /* How many times we have jumped.  */
    202  1.1  mrg static uint64_t master_state[] = {
    203  1.1  mrg   0xad63fa1ed3b55f36ULL, 0xd94473e78978b497ULL, 0xbc60592a98172477ULL,
    204  1.1  mrg   0xa3de7c6e81265301ULL, 0x586640c5e785af27ULL, 0x7a2a3f63b67ce5eaULL,
    205  1.1  mrg   0x9fde969f922d9b82ULL, 0xe6fe34379b3f3822ULL, 0x6c277eac3e99b6c2ULL,
    206  1.1  mrg   0x9197290ab0d3f069ULL, 0xdb227302f6c25576ULL, 0xee0209aee527fae9ULL,
    207  1.1  mrg   0x675666a793cd05b9ULL, 0xd048c99fbc70c20fULL, 0x775f8c3dba385ef5ULL,
    208  1.1  mrg   0x625288bc262faf33ULL
    209  1.1  mrg };
    210  1.1  mrg 
    211  1.1  mrg 
    212  1.1  mrg static __gthread_key_t rand_state_key;
    213  1.1  mrg 
    214  1.1  mrg static xorshift1024star_state*
    215  1.1  mrg get_rand_state (void)
    216  1.1  mrg {
    217  1.1  mrg   /* For single threaded apps.  */
    218  1.1  mrg   static xorshift1024star_state rand_state;
    219  1.1  mrg 
    220  1.1  mrg   if (__gthread_active_p ())
    221  1.1  mrg     {
    222  1.1  mrg       void* p = __gthread_getspecific (rand_state_key);
    223  1.1  mrg       if (!p)
    224  1.1  mrg 	{
    225  1.1  mrg 	  p = xcalloc (1, sizeof (xorshift1024star_state));
    226  1.1  mrg 	  __gthread_setspecific (rand_state_key, p);
    227  1.1  mrg 	}
    228  1.1  mrg       return p;
    229  1.1  mrg     }
    230  1.1  mrg   else
    231  1.1  mrg     return &rand_state;
    232  1.1  mrg }
    233  1.1  mrg 
    234  1.1  mrg 
    235  1.1  mrg static uint64_t
    236  1.1  mrg xorshift1024star (xorshift1024star_state* rs)
    237  1.1  mrg {
    238  1.1  mrg   int p = rs->p;
    239  1.1  mrg   const uint64_t s0 = rs->s[p];
    240  1.1  mrg   uint64_t s1 = rs->s[p = (p + 1) & 15];
    241  1.1  mrg   s1 ^= s1 << 31;
    242  1.1  mrg   rs->s[p] = s1 ^ s0 ^ (s1 >> 11) ^ (s0 >> 30);
    243  1.1  mrg   rs->p = p;
    244  1.1  mrg   return rs->s[p] * UINT64_C(1181783497276652981);
    245  1.1  mrg }
    246  1.1  mrg 
    247  1.1  mrg 
    248  1.1  mrg /* This is the jump function for the generator. It is equivalent to
    249  1.1  mrg    2^512 calls to xorshift1024star(); it can be used to generate 2^512
    250  1.1  mrg    non-overlapping subsequences for parallel computations. */
    251  1.1  mrg 
    252  1.1  mrg static void
    253  1.1  mrg jump (xorshift1024star_state* rs)
    254  1.1  mrg {
    255  1.1  mrg   static const uint64_t JUMP[] = {
    256  1.1  mrg     0x84242f96eca9c41dULL, 0xa3c65b8776f96855ULL, 0x5b34a39f070b5837ULL,
    257  1.1  mrg     0x4489affce4f31a1eULL, 0x2ffeeb0a48316f40ULL, 0xdc2d9891fe68c022ULL,
    258  1.1  mrg     0x3659132bb12fea70ULL, 0xaac17d8efa43cab8ULL, 0xc4cb815590989b13ULL,
    259  1.1  mrg     0x5ee975283d71c93bULL, 0x691548c86c1bd540ULL, 0x7910c41d10a1e6a5ULL,
    260  1.1  mrg     0x0b5fc64563b3e2a8ULL, 0x047f7684e9fc949dULL, 0xb99181f2d8f685caULL,
    261  1.1  mrg     0x284600e3f30e38c3ULL
    262  1.1  mrg   };
    263  1.1  mrg 
    264  1.1  mrg   uint64_t t[16] = { 0 };
    265  1.1  mrg   for(size_t i = 0; i < sizeof JUMP / sizeof *JUMP; i++)
    266  1.1  mrg     for(int b = 0; b < 64; b++)
    267  1.1  mrg       {
    268  1.1  mrg 	if (JUMP[i] & 1ULL << b)
    269  1.1  mrg 	  for(int j = 0; j < 16; j++)
    270  1.1  mrg 	    t[j] ^= rs->s[(j + rs->p) & 15];
    271  1.1  mrg 	xorshift1024star (rs);
    272  1.1  mrg       }
    273  1.1  mrg   for(int j = 0; j < 16; j++)
    274  1.1  mrg     rs->s[(j + rs->p) & 15] = t[j];
    275  1.1  mrg }
    276  1.1  mrg 
    277  1.1  mrg 
    278  1.1  mrg /* Splitmix64 recommended by xorshift author for initializing.  After
    279  1.1  mrg    getting one uint64_t value from the OS, this is used to fill in the
    280  1.1  mrg    rest of the state.  */
    281  1.1  mrg 
    282  1.1  mrg static uint64_t
    283  1.1  mrg splitmix64 (uint64_t x)
    284  1.1  mrg {
    285  1.1  mrg   uint64_t z = (x += 0x9e3779b97f4a7c15);
    286  1.1  mrg   z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
    287  1.1  mrg   z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
    288  1.1  mrg   return z ^ (z >> 31);
    289  1.1  mrg }
    290  1.1  mrg 
    291  1.1  mrg 
    292  1.1  mrg /* Get some random bytes from the operating system in order to seed
    293  1.1  mrg    the PRNG.  */
    294  1.1  mrg 
    295  1.1  mrg static int
    296  1.1  mrg getosrandom (void *buf, size_t buflen)
    297  1.1  mrg {
    298  1.1  mrg   /* rand_s is available in MinGW-w64 but not plain MinGW.  */
    299  1.1  mrg #if defined(__MINGW64_VERSION_MAJOR)
    300  1.1  mrg   unsigned int* b = buf;
    301  1.1  mrg   for (size_t i = 0; i < buflen / sizeof (unsigned int); i++)
    302  1.1  mrg     rand_s (&b[i]);
    303  1.1  mrg   return buflen;
    304  1.1  mrg #else
    305  1.1  mrg #ifdef HAVE_GETENTROPY
    306  1.1  mrg   if (getentropy (buf, buflen) == 0)
    307  1.1  mrg     return buflen;
    308  1.1  mrg #endif
    309  1.1  mrg   int flags = O_RDONLY;
    310  1.1  mrg #ifdef O_CLOEXEC
    311  1.1  mrg   flags |= O_CLOEXEC;
    312  1.1  mrg #endif
    313  1.1  mrg   int fd = open("/dev/urandom", flags);
    314  1.1  mrg   if (fd != -1)
    315  1.1  mrg     {
    316  1.1  mrg       int res = read(fd, buf, buflen);
    317  1.1  mrg       close (fd);
    318  1.1  mrg       return res;
    319  1.1  mrg     }
    320  1.1  mrg   uint64_t seed = 0x047f7684e9fc949dULL;
    321  1.1  mrg   time_t secs;
    322  1.1  mrg   long usecs;
    323  1.1  mrg   if (gf_gettime (&secs, &usecs) == 0)
    324  1.1  mrg     {
    325  1.1  mrg       seed ^= secs;
    326  1.1  mrg       seed ^= usecs;
    327  1.1  mrg     }
    328  1.1  mrg #ifdef HAVE_GETPID
    329  1.1  mrg   pid_t pid = getpid();
    330  1.1  mrg   seed ^= pid;
    331  1.1  mrg #endif
    332  1.1  mrg   size_t size = buflen < sizeof (uint64_t) ? buflen : sizeof (uint64_t);
    333  1.1  mrg   memcpy (buf, &seed, size);
    334  1.1  mrg   return size;
    335  1.1  mrg #endif /* __MINGW64_VERSION_MAJOR  */
    336  1.1  mrg }
    337  1.1  mrg 
    338  1.1  mrg 
    339  1.1  mrg /* Initialize the random number generator for the current thread,
    340  1.1  mrg    using the master state and the number of times we must jump.  */
    341  1.1  mrg 
    342  1.1  mrg static void
    343  1.1  mrg init_rand_state (xorshift1024star_state* rs, const bool locked)
    344  1.1  mrg {
    345  1.1  mrg   if (!locked)
    346  1.1  mrg     __gthread_mutex_lock (&random_lock);
    347  1.1  mrg   if (!master_init)
    348  1.1  mrg     {
    349  1.1  mrg       uint64_t os_seed;
    350  1.1  mrg       getosrandom (&os_seed, sizeof (os_seed));
    351  1.1  mrg       for (uint64_t i = 0; i < sizeof (master_state) / sizeof (uint64_t); i++)
    352  1.1  mrg 	{
    353  1.1  mrg 	  os_seed = splitmix64 (os_seed);
    354  1.1  mrg 	  master_state[i] = os_seed;
    355  1.1  mrg 	}
    356  1.1  mrg       njumps = 0;
    357  1.1  mrg       master_init = true;
    358  1.1  mrg     }
    359  1.1  mrg   memcpy (&rs->s, master_state, sizeof (master_state));
    360  1.1  mrg   unsigned n = njumps++;
    361  1.1  mrg   if (!locked)
    362  1.1  mrg     __gthread_mutex_unlock (&random_lock);
    363  1.1  mrg   for (unsigned i = 0; i < n; i++)
    364  1.1  mrg     jump (rs);
    365  1.1  mrg   rs->init = true;
    366  1.1  mrg }
    367  1.1  mrg 
    368  1.1  mrg 
    369  1.1  mrg /*  This function produces a REAL(4) value from the uniform distribution
    370  1.1  mrg     with range [0,1).  */
    371  1.1  mrg 
    372  1.1  mrg void
    373  1.1  mrg random_r4 (GFC_REAL_4 *x)
    374  1.1  mrg {
    375  1.1  mrg   xorshift1024star_state* rs = get_rand_state();
    376  1.1  mrg 
    377  1.1  mrg   if (unlikely (!rs->init))
    378  1.1  mrg     init_rand_state (rs, false);
    379  1.1  mrg   uint64_t r = xorshift1024star (rs);
    380  1.1  mrg   /* Take the higher bits, ensuring that a stream of real(4), real(8),
    381  1.1  mrg      and real(10) will be identical (except for precision).  */
    382  1.1  mrg   uint32_t high = (uint32_t) (r >> 32);
    383  1.1  mrg   rnumber_4 (x, high);
    384  1.1  mrg }
    385  1.1  mrg iexport(random_r4);
    386  1.1  mrg 
    387  1.1  mrg /*  This function produces a REAL(8) value from the uniform distribution
    388  1.1  mrg     with range [0,1).  */
    389  1.1  mrg 
    390  1.1  mrg void
    391  1.1  mrg random_r8 (GFC_REAL_8 *x)
    392  1.1  mrg {
    393  1.1  mrg   GFC_UINTEGER_8 r;
    394  1.1  mrg   xorshift1024star_state* rs = get_rand_state();
    395  1.1  mrg 
    396  1.1  mrg   if (unlikely (!rs->init))
    397  1.1  mrg     init_rand_state (rs, false);
    398  1.1  mrg   r = xorshift1024star (rs);
    399  1.1  mrg   rnumber_8 (x, r);
    400  1.1  mrg }
    401  1.1  mrg iexport(random_r8);
    402  1.1  mrg 
    403  1.1  mrg #ifdef HAVE_GFC_REAL_10
    404  1.1  mrg 
    405  1.1  mrg /*  This function produces a REAL(10) value from the uniform distribution
    406  1.1  mrg     with range [0,1).  */
    407  1.1  mrg 
    408  1.1  mrg void
    409  1.1  mrg random_r10 (GFC_REAL_10 *x)
    410  1.1  mrg {
    411  1.1  mrg   GFC_UINTEGER_8 r;
    412  1.1  mrg   xorshift1024star_state* rs = get_rand_state();
    413  1.1  mrg 
    414  1.1  mrg   if (unlikely (!rs->init))
    415  1.1  mrg     init_rand_state (rs, false);
    416  1.1  mrg   r = xorshift1024star (rs);
    417  1.1  mrg   rnumber_10 (x, r);
    418  1.1  mrg }
    419  1.1  mrg iexport(random_r10);
    420  1.1  mrg 
    421  1.1  mrg #endif
    422  1.1  mrg 
    423  1.1  mrg /*  This function produces a REAL(16) value from the uniform distribution
    424  1.1  mrg     with range [0,1).  */
    425  1.1  mrg 
    426  1.1  mrg #ifdef HAVE_GFC_REAL_16
    427  1.1  mrg 
    428  1.1  mrg void
    429  1.1  mrg random_r16 (GFC_REAL_16 *x)
    430  1.1  mrg {
    431  1.1  mrg   GFC_UINTEGER_8 r1, r2;
    432  1.1  mrg   xorshift1024star_state* rs = get_rand_state();
    433  1.1  mrg 
    434  1.1  mrg   if (unlikely (!rs->init))
    435  1.1  mrg     init_rand_state (rs, false);
    436  1.1  mrg   r1 = xorshift1024star (rs);
    437  1.1  mrg   r2 = xorshift1024star (rs);
    438  1.1  mrg   rnumber_16 (x, r1, r2);
    439  1.1  mrg }
    440  1.1  mrg iexport(random_r16);
    441  1.1  mrg 
    442  1.1  mrg 
    443  1.1  mrg #endif
    444  1.1  mrg 
    445  1.1  mrg /*  This function fills a REAL(4) array with values from the uniform
    446  1.1  mrg     distribution with range [0,1).  */
    447  1.1  mrg 
    448  1.1  mrg void
    449  1.1  mrg arandom_r4 (gfc_array_r4 *x)
    450  1.1  mrg {
    451  1.1  mrg   index_type count[GFC_MAX_DIMENSIONS];
    452  1.1  mrg   index_type extent[GFC_MAX_DIMENSIONS];
    453  1.1  mrg   index_type stride[GFC_MAX_DIMENSIONS];
    454  1.1  mrg   index_type stride0;
    455  1.1  mrg   index_type dim;
    456  1.1  mrg   GFC_REAL_4 *dest;
    457  1.1  mrg   xorshift1024star_state* rs = get_rand_state();
    458  1.1  mrg 
    459  1.1  mrg   dest = x->base_addr;
    460  1.1  mrg 
    461  1.1  mrg   dim = GFC_DESCRIPTOR_RANK (x);
    462  1.1  mrg 
    463  1.1  mrg   for (index_type n = 0; n < dim; n++)
    464  1.1  mrg     {
    465  1.1  mrg       count[n] = 0;
    466  1.1  mrg       stride[n] = GFC_DESCRIPTOR_STRIDE(x,n);
    467  1.1  mrg       extent[n] = GFC_DESCRIPTOR_EXTENT(x,n);
    468  1.1  mrg       if (extent[n] <= 0)
    469  1.1  mrg         return;
    470  1.1  mrg     }
    471  1.1  mrg 
    472  1.1  mrg   stride0 = stride[0];
    473  1.1  mrg 
    474  1.1  mrg   if (unlikely (!rs->init))
    475  1.1  mrg     init_rand_state (rs, false);
    476  1.1  mrg 
    477  1.1  mrg   while (dest)
    478  1.1  mrg     {
    479  1.1  mrg       /* random_r4 (dest);  */
    480  1.1  mrg       uint64_t r = xorshift1024star (rs);
    481  1.1  mrg       uint32_t high = (uint32_t) (r >> 32);
    482  1.1  mrg       rnumber_4 (dest, high);
    483  1.1  mrg 
    484  1.1  mrg       /* Advance to the next element.  */
    485  1.1  mrg       dest += stride0;
    486  1.1  mrg       count[0]++;
    487  1.1  mrg       /* Advance to the next source element.  */
    488  1.1  mrg       index_type n = 0;
    489  1.1  mrg       while (count[n] == extent[n])
    490  1.1  mrg         {
    491  1.1  mrg           /* When we get to the end of a dimension, reset it and increment
    492  1.1  mrg              the next dimension.  */
    493  1.1  mrg           count[n] = 0;
    494  1.1  mrg           /* We could precalculate these products, but this is a less
    495  1.1  mrg              frequently used path so probably not worth it.  */
    496  1.1  mrg           dest -= stride[n] * extent[n];
    497  1.1  mrg           n++;
    498  1.1  mrg           if (n == dim)
    499  1.1  mrg             {
    500  1.1  mrg               dest = NULL;
    501  1.1  mrg               break;
    502  1.1  mrg             }
    503  1.1  mrg           else
    504  1.1  mrg             {
    505  1.1  mrg               count[n]++;
    506  1.1  mrg               dest += stride[n];
    507  1.1  mrg             }
    508  1.1  mrg         }
    509  1.1  mrg     }
    510  1.1  mrg }
    511  1.1  mrg 
    512  1.1  mrg /*  This function fills a REAL(8) array with values from the uniform
    513  1.1  mrg     distribution with range [0,1).  */
    514  1.1  mrg 
    515  1.1  mrg void
    516  1.1  mrg arandom_r8 (gfc_array_r8 *x)
    517  1.1  mrg {
    518  1.1  mrg   index_type count[GFC_MAX_DIMENSIONS];
    519  1.1  mrg   index_type extent[GFC_MAX_DIMENSIONS];
    520  1.1  mrg   index_type stride[GFC_MAX_DIMENSIONS];
    521  1.1  mrg   index_type stride0;
    522  1.1  mrg   index_type dim;
    523  1.1  mrg   GFC_REAL_8 *dest;
    524  1.1  mrg   xorshift1024star_state* rs = get_rand_state();
    525  1.1  mrg 
    526  1.1  mrg   dest = x->base_addr;
    527  1.1  mrg 
    528  1.1  mrg   dim = GFC_DESCRIPTOR_RANK (x);
    529  1.1  mrg 
    530  1.1  mrg   for (index_type n = 0; n < dim; n++)
    531  1.1  mrg     {
    532  1.1  mrg       count[n] = 0;
    533  1.1  mrg       stride[n] = GFC_DESCRIPTOR_STRIDE(x,n);
    534  1.1  mrg       extent[n] = GFC_DESCRIPTOR_EXTENT(x,n);
    535  1.1  mrg       if (extent[n] <= 0)
    536  1.1  mrg         return;
    537  1.1  mrg     }
    538  1.1  mrg 
    539  1.1  mrg   stride0 = stride[0];
    540  1.1  mrg 
    541  1.1  mrg   if (unlikely (!rs->init))
    542  1.1  mrg     init_rand_state (rs, false);
    543  1.1  mrg 
    544  1.1  mrg   while (dest)
    545  1.1  mrg     {
    546  1.1  mrg       /* random_r8 (dest);  */
    547  1.1  mrg       uint64_t r = xorshift1024star (rs);
    548  1.1  mrg       rnumber_8 (dest, r);
    549  1.1  mrg 
    550  1.1  mrg       /* Advance to the next element.  */
    551  1.1  mrg       dest += stride0;
    552  1.1  mrg       count[0]++;
    553  1.1  mrg       /* Advance to the next source element.  */
    554  1.1  mrg       index_type n = 0;
    555  1.1  mrg       while (count[n] == extent[n])
    556  1.1  mrg         {
    557  1.1  mrg           /* When we get to the end of a dimension, reset it and increment
    558  1.1  mrg              the next dimension.  */
    559  1.1  mrg           count[n] = 0;
    560  1.1  mrg           /* We could precalculate these products, but this is a less
    561  1.1  mrg              frequently used path so probably not worth it.  */
    562  1.1  mrg           dest -= stride[n] * extent[n];
    563  1.1  mrg           n++;
    564  1.1  mrg           if (n == dim)
    565  1.1  mrg             {
    566  1.1  mrg               dest = NULL;
    567  1.1  mrg               break;
    568  1.1  mrg             }
    569  1.1  mrg           else
    570  1.1  mrg             {
    571  1.1  mrg               count[n]++;
    572  1.1  mrg               dest += stride[n];
    573  1.1  mrg             }
    574  1.1  mrg         }
    575  1.1  mrg     }
    576  1.1  mrg }
    577  1.1  mrg 
    578  1.1  mrg #ifdef HAVE_GFC_REAL_10
    579  1.1  mrg 
    580  1.1  mrg /*  This function fills a REAL(10) array with values from the uniform
    581  1.1  mrg     distribution with range [0,1).  */
    582  1.1  mrg 
    583  1.1  mrg void
    584  1.1  mrg arandom_r10 (gfc_array_r10 *x)
    585  1.1  mrg {
    586  1.1  mrg   index_type count[GFC_MAX_DIMENSIONS];
    587  1.1  mrg   index_type extent[GFC_MAX_DIMENSIONS];
    588  1.1  mrg   index_type stride[GFC_MAX_DIMENSIONS];
    589  1.1  mrg   index_type stride0;
    590  1.1  mrg   index_type dim;
    591  1.1  mrg   GFC_REAL_10 *dest;
    592  1.1  mrg   xorshift1024star_state* rs = get_rand_state();
    593  1.1  mrg 
    594  1.1  mrg   dest = x->base_addr;
    595  1.1  mrg 
    596  1.1  mrg   dim = GFC_DESCRIPTOR_RANK (x);
    597  1.1  mrg 
    598  1.1  mrg   for (index_type n = 0; n < dim; n++)
    599  1.1  mrg     {
    600  1.1  mrg       count[n] = 0;
    601  1.1  mrg       stride[n] = GFC_DESCRIPTOR_STRIDE(x,n);
    602  1.1  mrg       extent[n] = GFC_DESCRIPTOR_EXTENT(x,n);
    603  1.1  mrg       if (extent[n] <= 0)
    604  1.1  mrg         return;
    605  1.1  mrg     }
    606  1.1  mrg 
    607  1.1  mrg   stride0 = stride[0];
    608  1.1  mrg 
    609  1.1  mrg   if (unlikely (!rs->init))
    610  1.1  mrg     init_rand_state (rs, false);
    611  1.1  mrg 
    612  1.1  mrg   while (dest)
    613  1.1  mrg     {
    614  1.1  mrg       /* random_r10 (dest);  */
    615  1.1  mrg       uint64_t r = xorshift1024star (rs);
    616  1.1  mrg       rnumber_10 (dest, r);
    617  1.1  mrg 
    618  1.1  mrg       /* Advance to the next element.  */
    619  1.1  mrg       dest += stride0;
    620  1.1  mrg       count[0]++;
    621  1.1  mrg       /* Advance to the next source element.  */
    622  1.1  mrg       index_type n = 0;
    623  1.1  mrg       while (count[n] == extent[n])
    624  1.1  mrg         {
    625  1.1  mrg           /* When we get to the end of a dimension, reset it and increment
    626  1.1  mrg              the next dimension.  */
    627  1.1  mrg           count[n] = 0;
    628  1.1  mrg           /* We could precalculate these products, but this is a less
    629  1.1  mrg              frequently used path so probably not worth it.  */
    630  1.1  mrg           dest -= stride[n] * extent[n];
    631  1.1  mrg           n++;
    632  1.1  mrg           if (n == dim)
    633  1.1  mrg             {
    634  1.1  mrg               dest = NULL;
    635  1.1  mrg               break;
    636  1.1  mrg             }
    637  1.1  mrg           else
    638  1.1  mrg             {
    639  1.1  mrg               count[n]++;
    640  1.1  mrg               dest += stride[n];
    641  1.1  mrg             }
    642  1.1  mrg         }
    643  1.1  mrg     }
    644  1.1  mrg }
    645  1.1  mrg 
    646  1.1  mrg #endif
    647  1.1  mrg 
    648  1.1  mrg #ifdef HAVE_GFC_REAL_16
    649  1.1  mrg 
    650  1.1  mrg /*  This function fills a REAL(16) array with values from the uniform
    651  1.1  mrg     distribution with range [0,1).  */
    652  1.1  mrg 
    653  1.1  mrg void
    654  1.1  mrg arandom_r16 (gfc_array_r16 *x)
    655  1.1  mrg {
    656  1.1  mrg   index_type count[GFC_MAX_DIMENSIONS];
    657  1.1  mrg   index_type extent[GFC_MAX_DIMENSIONS];
    658  1.1  mrg   index_type stride[GFC_MAX_DIMENSIONS];
    659  1.1  mrg   index_type stride0;
    660  1.1  mrg   index_type dim;
    661  1.1  mrg   GFC_REAL_16 *dest;
    662  1.1  mrg   xorshift1024star_state* rs = get_rand_state();
    663  1.1  mrg 
    664  1.1  mrg   dest = x->base_addr;
    665  1.1  mrg 
    666  1.1  mrg   dim = GFC_DESCRIPTOR_RANK (x);
    667  1.1  mrg 
    668  1.1  mrg   for (index_type n = 0; n < dim; n++)
    669  1.1  mrg     {
    670  1.1  mrg       count[n] = 0;
    671  1.1  mrg       stride[n] = GFC_DESCRIPTOR_STRIDE(x,n);
    672  1.1  mrg       extent[n] = GFC_DESCRIPTOR_EXTENT(x,n);
    673  1.1  mrg       if (extent[n] <= 0)
    674  1.1  mrg         return;
    675  1.1  mrg     }
    676  1.1  mrg 
    677  1.1  mrg   stride0 = stride[0];
    678  1.1  mrg 
    679  1.1  mrg   if (unlikely (!rs->init))
    680  1.1  mrg     init_rand_state (rs, false);
    681  1.1  mrg 
    682  1.1  mrg   while (dest)
    683  1.1  mrg     {
    684  1.1  mrg       /* random_r16 (dest);  */
    685  1.1  mrg       uint64_t r1 = xorshift1024star (rs);
    686  1.1  mrg       uint64_t r2 = xorshift1024star (rs);
    687  1.1  mrg       rnumber_16 (dest, r1, r2);
    688  1.1  mrg 
    689  1.1  mrg       /* Advance to the next element.  */
    690  1.1  mrg       dest += stride0;
    691  1.1  mrg       count[0]++;
    692  1.1  mrg       /* Advance to the next source element.  */
    693  1.1  mrg       index_type n = 0;
    694  1.1  mrg       while (count[n] == extent[n])
    695  1.1  mrg         {
    696  1.1  mrg           /* When we get to the end of a dimension, reset it and increment
    697  1.1  mrg              the next dimension.  */
    698  1.1  mrg           count[n] = 0;
    699  1.1  mrg           /* We could precalculate these products, but this is a less
    700  1.1  mrg              frequently used path so probably not worth it.  */
    701  1.1  mrg           dest -= stride[n] * extent[n];
    702  1.1  mrg           n++;
    703  1.1  mrg           if (n == dim)
    704  1.1  mrg             {
    705  1.1  mrg               dest = NULL;
    706  1.1  mrg               break;
    707  1.1  mrg             }
    708  1.1  mrg           else
    709  1.1  mrg             {
    710  1.1  mrg               count[n]++;
    711  1.1  mrg               dest += stride[n];
    712  1.1  mrg             }
    713  1.1  mrg         }
    714  1.1  mrg     }
    715  1.1  mrg }
    716  1.1  mrg 
    717  1.1  mrg #endif
    718  1.1  mrg 
    719  1.1  mrg 
    720  1.1  mrg /* Number of elements in master_state array.  */
    721  1.1  mrg #define SZU64 (sizeof (master_state) / sizeof (uint64_t))
    722  1.1  mrg 
    723  1.1  mrg 
    724  1.1  mrg /* Keys for scrambling the seed in order to avoid poor seeds.  */
    725  1.1  mrg 
    726  1.1  mrg static const uint64_t xor_keys[] = {
    727  1.1  mrg   0xbd0c5b6e50c2df49ULL, 0xd46061cd46e1df38ULL, 0xbb4f4d4ed6103544ULL,
    728  1.1  mrg   0x114a583d0756ad39ULL, 0x4b5ad8623d0aaab6ULL, 0x3f2ed7afbe0c0f21ULL,
    729  1.1  mrg   0xdec83fd65f113445ULL, 0x3824f8fbc4f10d24ULL, 0x5d9025af05878911ULL,
    730  1.1  mrg   0x500bc46b540340e9ULL, 0x8bd53298e0d00530ULL, 0x57886e40a952e06aULL,
    731  1.1  mrg   0x926e76c88e31cdb6ULL, 0xbd0724dac0a3a5f9ULL, 0xc5c8981b858ab796ULL,
    732  1.1  mrg   0xbb12ab2694c2b32cULL
    733  1.1  mrg };
    734  1.1  mrg 
    735  1.1  mrg 
    736  1.1  mrg /* Since a XOR cipher is symmetric, we need only one routine, and we
    737  1.1  mrg    can use it both for encryption and decryption.  */
    738  1.1  mrg 
    739  1.1  mrg static void
    740  1.1  mrg scramble_seed (uint64_t *dest, const uint64_t *src)
    741  1.1  mrg {
    742  1.1  mrg   for (size_t i = 0; i < SZU64; i++)
    743  1.1  mrg     dest[i] = src[i] ^ xor_keys[i];
    744  1.1  mrg }
    745  1.1  mrg 
    746  1.1  mrg 
    747  1.1  mrg /* random_seed is used to seed the PRNG with either a default
    748  1.1  mrg    set of seeds or user specified set of seeds.  random_seed
    749  1.1  mrg    must be called with no argument or exactly one argument.  */
    750  1.1  mrg 
    751  1.1  mrg void
    752  1.1  mrg random_seed_i4 (GFC_INTEGER_4 *size, gfc_array_i4 *put, gfc_array_i4 *get)
    753  1.1  mrg {
    754  1.1  mrg   uint64_t seed[SZU64];
    755  1.1  mrg #define SZ (sizeof (master_state) / sizeof (GFC_INTEGER_4))
    756  1.1  mrg 
    757  1.1  mrg   /* Check that we only have one argument present.  */
    758  1.1  mrg   if ((size ? 1 : 0) + (put ? 1 : 0) + (get ? 1 : 0) > 1)
    759  1.1  mrg     runtime_error ("RANDOM_SEED should have at most one argument present.");
    760  1.1  mrg 
    761  1.1  mrg   if (size != NULL)
    762  1.1  mrg     *size = SZ + 1;
    763  1.1  mrg 
    764  1.1  mrg   xorshift1024star_state* rs = get_rand_state();
    765  1.1  mrg 
    766  1.1  mrg   /* Return the seed to GET data.  */
    767  1.1  mrg   if (get != NULL)
    768  1.1  mrg     {
    769  1.1  mrg       /* If the rank of the array is not 1, abort.  */
    770  1.1  mrg       if (GFC_DESCRIPTOR_RANK (get) != 1)
    771  1.1  mrg 	runtime_error ("Array rank of GET is not 1.");
    772  1.1  mrg 
    773  1.1  mrg       /* If the array is too small, abort.  */
    774  1.1  mrg       if (GFC_DESCRIPTOR_EXTENT(get,0) < (index_type) SZ + 1)
    775  1.1  mrg 	runtime_error ("Array size of GET is too small.");
    776  1.1  mrg 
    777  1.1  mrg       if (!rs->init)
    778  1.1  mrg 	init_rand_state (rs, false);
    779  1.1  mrg 
    780  1.1  mrg       /* Unscramble the seed.  */
    781  1.1  mrg       scramble_seed (seed, rs->s);
    782  1.1  mrg 
    783  1.1  mrg       /*  Then copy it back to the user variable.  */
    784  1.1  mrg       for (size_t i = 0; i < SZ ; i++)
    785  1.1  mrg 	memcpy (&(get->base_addr[(SZ - 1 - i) * GFC_DESCRIPTOR_STRIDE(get,0)]),
    786  1.1  mrg 		(unsigned char*) seed + i * sizeof(GFC_UINTEGER_4),
    787  1.1  mrg                sizeof(GFC_UINTEGER_4));
    788  1.1  mrg 
    789  1.1  mrg       /* Finally copy the value of p after the seed.  */
    790  1.1  mrg       get->base_addr[SZ * GFC_DESCRIPTOR_STRIDE(get, 0)] = rs->p;
    791  1.1  mrg     }
    792  1.1  mrg 
    793  1.1  mrg   else
    794  1.1  mrg     {
    795  1.1  mrg   __gthread_mutex_lock (&random_lock);
    796  1.1  mrg 
    797  1.1  mrg   /* From the standard: "If no argument is present, the processor assigns
    798  1.1  mrg      a processor-dependent value to the seed."  */
    799  1.1  mrg   if (size == NULL && put == NULL && get == NULL)
    800  1.1  mrg     {
    801  1.1  mrg       master_init = false;
    802  1.1  mrg       init_rand_state (rs, true);
    803  1.1  mrg     }
    804  1.1  mrg 
    805  1.1  mrg   if (put != NULL)
    806  1.1  mrg     {
    807  1.1  mrg       /* If the rank of the array is not 1, abort.  */
    808  1.1  mrg       if (GFC_DESCRIPTOR_RANK (put) != 1)
    809  1.1  mrg         runtime_error ("Array rank of PUT is not 1.");
    810  1.1  mrg 
    811  1.1  mrg       /* If the array is too small, abort.  */
    812  1.1  mrg       if (GFC_DESCRIPTOR_EXTENT(put,0) < (index_type) SZ + 1)
    813  1.1  mrg         runtime_error ("Array size of PUT is too small.");
    814  1.1  mrg 
    815  1.1  mrg       /*  We copy the seed given by the user.  */
    816  1.1  mrg       for (size_t i = 0; i < SZ; i++)
    817  1.1  mrg 	memcpy ((unsigned char*) seed + i * sizeof(GFC_UINTEGER_4),
    818  1.1  mrg 		&(put->base_addr[(SZ - 1 - i) * GFC_DESCRIPTOR_STRIDE(put,0)]),
    819  1.1  mrg 		sizeof(GFC_UINTEGER_4));
    820  1.1  mrg 
    821  1.1  mrg       /* We put it after scrambling the bytes, to paper around users who
    822  1.1  mrg 	 provide seeds with quality only in the lower or upper part.  */
    823  1.1  mrg       scramble_seed (master_state, seed);
    824  1.1  mrg       njumps = 0;
    825  1.1  mrg       master_init = true;
    826  1.1  mrg       init_rand_state (rs, true);
    827  1.1  mrg 
    828  1.1  mrg       rs->p = put->base_addr[SZ * GFC_DESCRIPTOR_STRIDE(put, 0)] & 15;
    829  1.1  mrg     }
    830  1.1  mrg 
    831  1.1  mrg   __gthread_mutex_unlock (&random_lock);
    832  1.1  mrg     }
    833  1.1  mrg #undef SZ
    834  1.1  mrg }
    835  1.1  mrg iexport(random_seed_i4);
    836  1.1  mrg 
    837  1.1  mrg 
    838  1.1  mrg void
    839  1.1  mrg random_seed_i8 (GFC_INTEGER_8 *size, gfc_array_i8 *put, gfc_array_i8 *get)
    840  1.1  mrg {
    841  1.1  mrg   uint64_t seed[SZU64];
    842  1.1  mrg 
    843  1.1  mrg   /* Check that we only have one argument present.  */
    844  1.1  mrg   if ((size ? 1 : 0) + (put ? 1 : 0) + (get ? 1 : 0) > 1)
    845  1.1  mrg     runtime_error ("RANDOM_SEED should have at most one argument present.");
    846  1.1  mrg 
    847  1.1  mrg #define SZ (sizeof (master_state) / sizeof (GFC_INTEGER_8))
    848  1.1  mrg   if (size != NULL)
    849  1.1  mrg     *size = SZ + 1;
    850  1.1  mrg 
    851  1.1  mrg   xorshift1024star_state* rs = get_rand_state();
    852  1.1  mrg 
    853  1.1  mrg   /* Return the seed to GET data.  */
    854  1.1  mrg   if (get != NULL)
    855  1.1  mrg     {
    856  1.1  mrg       /* If the rank of the array is not 1, abort.  */
    857  1.1  mrg       if (GFC_DESCRIPTOR_RANK (get) != 1)
    858  1.1  mrg 	runtime_error ("Array rank of GET is not 1.");
    859  1.1  mrg 
    860  1.1  mrg       /* If the array is too small, abort.  */
    861  1.1  mrg       if (GFC_DESCRIPTOR_EXTENT(get,0) < (index_type) SZ + 1)
    862  1.1  mrg 	runtime_error ("Array size of GET is too small.");
    863  1.1  mrg 
    864  1.1  mrg       if (!rs->init)
    865  1.1  mrg 	init_rand_state (rs, false);
    866  1.1  mrg 
    867  1.1  mrg       /* Unscramble the seed.  */
    868  1.1  mrg       scramble_seed (seed, rs->s);
    869  1.1  mrg 
    870  1.1  mrg       /*  This code now should do correct strides.  */
    871  1.1  mrg       for (size_t i = 0; i < SZ; i++)
    872  1.1  mrg 	memcpy (&(get->base_addr[i * GFC_DESCRIPTOR_STRIDE(get,0)]), &seed[i],
    873  1.1  mrg 		sizeof (GFC_UINTEGER_8));
    874  1.1  mrg 
    875  1.1  mrg       get->base_addr[SZ * GFC_DESCRIPTOR_STRIDE(get, 0)] = rs->p;
    876  1.1  mrg     }
    877  1.1  mrg 
    878  1.1  mrg   else
    879  1.1  mrg     {
    880  1.1  mrg   __gthread_mutex_lock (&random_lock);
    881  1.1  mrg 
    882  1.1  mrg   /* From the standard: "If no argument is present, the processor assigns
    883  1.1  mrg      a processor-dependent value to the seed."  */
    884  1.1  mrg   if (size == NULL && put == NULL && get == NULL)
    885  1.1  mrg     {
    886  1.1  mrg       master_init = false;
    887  1.1  mrg       init_rand_state (rs, true);
    888  1.1  mrg     }
    889  1.1  mrg 
    890  1.1  mrg   if (put != NULL)
    891  1.1  mrg     {
    892  1.1  mrg       /* If the rank of the array is not 1, abort.  */
    893  1.1  mrg       if (GFC_DESCRIPTOR_RANK (put) != 1)
    894  1.1  mrg         runtime_error ("Array rank of PUT is not 1.");
    895  1.1  mrg 
    896  1.1  mrg       /* If the array is too small, abort.  */
    897  1.1  mrg       if (GFC_DESCRIPTOR_EXTENT(put,0) < (index_type) SZ + 1)
    898  1.1  mrg         runtime_error ("Array size of PUT is too small.");
    899  1.1  mrg 
    900  1.1  mrg       /*  This code now should do correct strides.  */
    901  1.1  mrg       for (size_t i = 0; i < SZ; i++)
    902  1.1  mrg 	memcpy (&seed[i], &(put->base_addr[i * GFC_DESCRIPTOR_STRIDE(put,0)]),
    903  1.1  mrg 		sizeof (GFC_UINTEGER_8));
    904  1.1  mrg 
    905  1.1  mrg       scramble_seed (master_state, seed);
    906  1.1  mrg       njumps = 0;
    907  1.1  mrg       master_init = true;
    908  1.1  mrg       init_rand_state (rs, true);
    909  1.1  mrg       rs->p = put->base_addr[SZ * GFC_DESCRIPTOR_STRIDE(put, 0)] & 15;
    910  1.1  mrg      }
    911  1.1  mrg 
    912  1.1  mrg 
    913  1.1  mrg   __gthread_mutex_unlock (&random_lock);
    914  1.1  mrg     }
    915  1.1  mrg }
    916  1.1  mrg iexport(random_seed_i8);
    917  1.1  mrg 
    918  1.1  mrg 
    919  1.1  mrg #if !defined __GTHREAD_MUTEX_INIT || defined __GTHREADS
    920  1.1  mrg static void __attribute__((constructor))
    921  1.1  mrg constructor_random (void)
    922  1.1  mrg {
    923  1.1  mrg #ifndef __GTHREAD_MUTEX_INIT
    924  1.1  mrg   __GTHREAD_MUTEX_INIT_FUNCTION (&random_lock);
    925  1.1  mrg #endif
    926  1.1  mrg   if (__gthread_active_p ())
    927  1.1  mrg     __gthread_key_create (&rand_state_key, &free);
    928  1.1  mrg }
    929  1.1  mrg #endif
    930  1.1  mrg 
    931  1.1  mrg #ifdef __GTHREADS
    932  1.1  mrg static void __attribute__((destructor))
    933  1.1  mrg destructor_random (void)
    934  1.1  mrg {
    935  1.1  mrg   if (__gthread_active_p ())
    936  1.1  mrg     __gthread_key_delete (rand_state_key);
    937  1.1  mrg }
    938  1.1  mrg #endif
    939