1 /* Implementation of the RANDOM intrinsics
2 Copyright 2002, 2004 Free Software Foundation, Inc.
3 Contributed by Lars Segerlund <seger@linuxmail.org>
6 This file is part of the GNU Fortran 95 runtime library (libgfortran).
8 Libgfortran is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 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 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public
19 License along with libgfor; see the file COPYING.LIB. If not,
20 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA. */
25 /* The Mersenne Twister code is currently commented out due to
27 (1) Simple user specified seeds lead to really bad sequences for
28 nearly 100000 random numbers.
29 (2) open(), read(), and close() are not properly declared via header
31 (3) The global index i is abused and causes unexpected behavior with
35 The algorithm was taken from the paper :
37 Mersenne Twister: 623-dimensionally equidistributed
38 uniform pseudorandom generator.
43 Which appeared in the: ACM Transactions on Modelling and Computer
44 Simulations: Special Issue on Uniform Random Number
45 Generation. ( Early in 1998 ). */
51 #include <sys/types.h>
59 #include "libgfortran.h"
61 /*Use the 'big' generator by default ( period -> 2**19937 ). */
65 /* Define the necessary constants for the algorithm. */
70 N
= 624, M
= 397, R
= 19, TU
= 11, TS
= 7, TT
= 15, TL
= 17
72 #define M_A 0x9908B0DF
73 #define T_B 0x9D2C5680
74 #define T_C 0xEFC60000
78 N
= 351, M
= 175, R
= 19, TU
= 11, TS
= 7, TT
= 15, TL
= 17
80 #define M_A 0xE4BD75F5
81 #define T_B 0x655E5280
82 #define T_C 0xFFD58000
86 static unsigned int seed
[N
];
88 /* This is the routine which handles the seeding of the generator,
89 and also reading and writing of the seed. */
92 random_seed (GFC_INTEGER_4
* size
, const gfc_array_i4
* put
,
93 const gfc_array_i4
* get
)
95 /* Initialize the seed in system dependent manner. */
96 if (get
== NULL
&& put
== NULL
&& size
== NULL
)
99 fd
= open ("/dev/urandom", O_RDONLY
);
102 /* We dont have urandom. */
103 GFC_UINTEGER_4 s
= (GFC_UINTEGER_4
) seed
;
104 for (i
= 0; i
< N
; i
++)
106 s
= s
* 29943829 - 1;
112 /* Using urandom, might have a length issue. */
113 read (fd
, &seed
[0], sizeof (GFC_UINTEGER_4
) * N
);
119 /* Return the size of the seed */
126 /* if we have gotten to this pount we have a get or put
127 * now we check it the array fulfills the demands in the standard .
130 /* Set the seed to PUT data */
133 /* if the rank of the array is not 1 abort */
134 if (GFC_DESCRIPTOR_RANK (put
) != 1)
137 /* if the array is too small abort */
138 if (((put
->dim
[0].ubound
+ 1 - put
->dim
[0].lbound
)) < N
)
141 /* If this is the case the array is a temporary */
142 if (put
->dim
[0].stride
== 0)
145 /* This code now should do correct strides. */
146 for (i
= 0; i
< N
; i
++)
147 seed
[i
] = put
->data
[i
* put
->dim
[0].stride
];
150 /* Return the seed to GET data */
153 /* if the rank of the array is not 1 abort */
154 if (GFC_DESCRIPTOR_RANK (get
) != 1)
157 /* if the array is too small abort */
158 if (((get
->dim
[0].ubound
+ 1 - get
->dim
[0].lbound
)) < N
)
161 /* If this is the case the array is a temporary */
162 if (get
->dim
[0].stride
== 0)
165 /* This code now should do correct strides. */
166 for (i
= 0; i
< N
; i
++)
167 get
->data
[i
* get
->dim
[0].stride
] = seed
[i
];
171 /* Here is the internal routine which generates the random numbers
172 in 'batches' based upon the need for a new batch.
173 It's an integer based routine known as 'Mersenne Twister'.
174 This implementation still lacks 'tempering' and a good verification,
175 but gives very good metrics. */
178 random_generate (void)
183 /* Generate batch of N. */
185 for (k
= 0, m
= M
; k
< N
- 1; k
++)
187 y
= (seed
[k
] & (-1 << R
)) | (seed
[k
+ 1] & ((1u << R
) - 1));
188 seed
[k
] = seed
[m
] ^ (y
>> 1) ^ (-(GFC_INTEGER_4
) (y
& 1) & M_A
);
193 y
= (seed
[N
- 1] & (-1 << R
)) | (seed
[0] & ((1u << R
) - 1));
194 seed
[N
- 1] = seed
[M
- 1] ^ (y
>> 1) ^ (-(GFC_INTEGER_4
) (y
& 1) & M_A
);
198 /* A routine to return a REAL(KIND=4). */
200 #define random_r4 prefix(random_r4)
202 random_r4 (GFC_REAL_4
* harv
)
204 /* Regenerate if we need to. */
208 /* Convert uint32 to REAL(KIND=4). */
209 *harv
= (GFC_REAL_4
) ((GFC_REAL_4
) (GFC_UINTEGER_4
) seed
[i
++] /
210 (GFC_REAL_4
) (~(GFC_UINTEGER_4
) 0));
213 /* A routine to return a REAL(KIND=8). */
215 #define random_r8 prefix(random_r8)
217 random_r8 (GFC_REAL_8
* harv
)
219 /* Regenerate if we need to, may waste one 32-bit value. */
223 /* Convert two uint32 to a REAL(KIND=8). */
224 *harv
= ((GFC_REAL_8
) ((((GFC_UINTEGER_8
) seed
[i
+1]) << 32) + seed
[i
])) /
225 (GFC_REAL_8
) (~(GFC_UINTEGER_8
) 0);
229 /* Code to handle arrays will follow here. */
231 /* REAL(KIND=4) REAL array. */
233 #define arandom_r4 prefix(arandom_r4)
235 arandom_r4 (gfc_array_r4
* harv
)
237 index_type count
[GFC_MAX_DIMENSIONS
- 1];
238 index_type extent
[GFC_MAX_DIMENSIONS
- 1];
239 index_type stride
[GFC_MAX_DIMENSIONS
- 1];
247 if (harv
->dim
[0].stride
== 0)
248 harv
->dim
[0].stride
= 1;
250 dim
= GFC_DESCRIPTOR_RANK (harv
);
252 for (n
= 0; n
< dim
; n
++)
255 stride
[n
] = harv
->dim
[n
].stride
;
256 extent
[n
] = harv
->dim
[n
].ubound
+ 1 - harv
->dim
[n
].lbound
;
265 /* Set the elements. */
267 /* regenerate if we need to */
271 /* Convert uint32 to float in a hopefully g95 compiant manner */
272 *dest
= (GFC_REAL_4
) ((GFC_REAL_4
) (GFC_UINTEGER_4
) seed
[i
++] /
273 (GFC_REAL_4
) (~(GFC_UINTEGER_4
) 0));
275 /* Advance to the next element. */
278 /* Advance to the next source element. */
280 while (count
[n
] == extent
[n
])
282 /* When we get to the end of a dimension,
283 reset it and increment
284 the next dimension. */
286 /* We could precalculate these products,
288 frequently used path so proabably not worth it. */
289 dest
-= stride
[n
] * extent
[n
];
305 /* REAL(KIND=8) array. */
307 #define arandom_r8 prefix(arandom_r8)
309 arandom_r8 (gfc_array_r8
* harv
)
311 index_type count
[GFC_MAX_DIMENSIONS
- 1];
312 index_type extent
[GFC_MAX_DIMENSIONS
- 1];
313 index_type stride
[GFC_MAX_DIMENSIONS
- 1];
321 if (harv
->dim
[0].stride
== 0)
322 harv
->dim
[0].stride
= 1;
324 dim
= GFC_DESCRIPTOR_RANK (harv
);
326 for (n
= 0; n
< dim
; n
++)
329 stride
[n
] = harv
->dim
[n
].stride
;
330 extent
[n
] = harv
->dim
[n
].ubound
+ 1 - harv
->dim
[n
].lbound
;
339 /* Set the elements. */
341 /* regenerate if we need to, may waste one 32-bit value */
345 /* Convert two uint32 to a REAL(KIND=8). */
346 *dest
= ((GFC_REAL_8
) ((((GFC_UINTEGER_8
) seed
[i
+1]) << 32) + seed
[i
])) /
347 (GFC_REAL_8
) (~(GFC_UINTEGER_8
) 0);
350 /* Advance to the next element. */
353 /* Advance to the next source element. */
355 while (count
[n
] == extent
[n
])
357 /* When we get to the end of a dimension,
358 reset it and increment
359 the next dimension. */
361 /* We could precalculate these products,
363 frequently used path so proabably not worth it. */
364 dest
-= stride
[n
] * extent
[n
];
379 #endif /* Mersenne Twister code */
382 /* George Marsaglia's KISS (Keep It Simple Stupid) random number generator.
386 (1) The congruential generator x(n)=69069*x(n-1)+1327217885 with a period
388 (2) A 3-shift shift-register generator with a period of 2^32-1,
389 (3) Two 16-bit multiply-with-carry generators with a period of
390 597273182964842497 > 2^59.
392 The overall period exceeds 2^123.
394 http://www.ciphersbyritter.com/NEWS4/RANDC.HTM#369F6FCA.74C7C041@stat.fsu.edu
396 The above web site has an archive of a newsgroup posting from George
397 Marsaglia with the statement:
399 Subject: Random numbers for C: Improvements.
400 Date: Fri, 15 Jan 1999 11:41:47 -0500
401 From: George Marsaglia <geo@stat.fsu.edu>
402 Message-ID: <369F6FCA.74C7C041@stat.fsu.edu>
403 References: <369B5E30.65A55FD1@stat.fsu.edu>
404 Newsgroups: sci.stat.math,sci.math,sci.math.numer-analysis
407 As I hoped, several suggestions have led to
408 improvements in the code for RNG's I proposed for
409 use in C. (See the thread "Random numbers for C: Some
410 suggestions" in previous postings.) The improved code
413 A question of copyright has also been raised. Unlike
414 DIEHARD, there is no copyright on the code below. You
415 are free to use it in any way you want, but you may
416 wish to acknowledge the source, as a courtesy.
418 "There is no copyright on the code below." included the original
422 #include "libgfortran.h"
424 #define GFC_SL(k, n) ((k)^((k)<<(n)))
425 #define GFC_SR(k, n) ((k)^((k)>>(n)))
427 static const GFC_INTEGER_4 kiss_size
= 4;
428 #define KISS_DEFAULT_SEED {123456789, 362436069, 521288629, 916191069};
429 static const GFC_UINTEGER_4 kiss_default_seed
[4] = KISS_DEFAULT_SEED
;
430 static GFC_UINTEGER_4 kiss_seed
[4] = KISS_DEFAULT_SEED
;
432 /* kiss_random_kernel() returns an integer value in the range of
433 (0, GFC_UINTEGER_4_HUGE]. The distribution of pseudorandom numbers
434 should be uniform. */
436 static GFC_UINTEGER_4
437 kiss_random_kernel(void)
442 kiss_seed
[0] = 69069 * kiss_seed
[0] + 1327217885;
443 kiss_seed
[1] = GFC_SL(GFC_SR(GFC_SL(kiss_seed
[1],13),17),5);
444 kiss_seed
[2] = 18000 * (kiss_seed
[2] & 65535) + (kiss_seed
[2] >> 16);
445 kiss_seed
[3] = 30903 * (kiss_seed
[3] & 65535) + (kiss_seed
[3] >> 16);
446 kiss
= kiss_seed
[0] + kiss_seed
[1] + (kiss_seed
[2] << 16) + kiss_seed
[3];
452 /* This function produces a REAL(4) value in the uniform distribution
456 prefix(random_r4
) (GFC_REAL_4
*x
)
463 kiss
= kiss_random_kernel ();
464 *x
= (GFC_REAL_4
)kiss
/ (GFC_REAL_4
)(~(GFC_UINTEGER_4
) 0);
470 /* This function produces a REAL(8) value from the uniform distribution
474 prefix(random_r8
) (GFC_REAL_8
*x
)
481 kiss
= (((GFC_UINTEGER_8
)kiss_random_kernel ()) << 32)
482 + kiss_random_kernel ();
483 *x
= (GFC_REAL_8
)kiss
/ (GFC_REAL_8
)(~(GFC_UINTEGER_8
) 0);
489 /* This function fills a REAL(4) array with values from the uniform
490 distribution with range [0,1). */
493 prefix(arandom_r4
) (gfc_array_r4
*x
)
496 index_type count
[GFC_MAX_DIMENSIONS
- 1];
497 index_type extent
[GFC_MAX_DIMENSIONS
- 1];
498 index_type stride
[GFC_MAX_DIMENSIONS
- 1];
506 if (x
->dim
[0].stride
== 0)
507 x
->dim
[0].stride
= 1;
509 dim
= GFC_DESCRIPTOR_RANK (x
);
511 for (n
= 0; n
< dim
; n
++)
514 stride
[n
] = x
->dim
[n
].stride
;
515 extent
[n
] = x
->dim
[n
].ubound
+ 1 - x
->dim
[n
].lbound
;
524 prefix(random_r4
) (dest
);
526 /* Advance to the next element. */
529 /* Advance to the next source element. */
531 while (count
[n
] == extent
[n
])
533 /* When we get to the end of a dimension, reset it and increment
534 the next dimension. */
536 /* We could precalculate these products, but this is a less
537 frequently used path so probably not worth it. */
538 dest
-= stride
[n
] * extent
[n
];
554 /* This function fills a REAL(8) array with valuse from the uniform
555 distribution with range [0,1). */
558 prefix(arandom_r8
) (gfc_array_r8
*x
)
561 index_type count
[GFC_MAX_DIMENSIONS
- 1];
562 index_type extent
[GFC_MAX_DIMENSIONS
- 1];
563 index_type stride
[GFC_MAX_DIMENSIONS
- 1];
571 if (x
->dim
[0].stride
== 0)
572 x
->dim
[0].stride
= 1;
574 dim
= GFC_DESCRIPTOR_RANK (x
);
576 for (n
= 0; n
< dim
; n
++)
579 stride
[n
] = x
->dim
[n
].stride
;
580 extent
[n
] = x
->dim
[n
].ubound
+ 1 - x
->dim
[n
].lbound
;
589 prefix(random_r8
) (dest
);
591 /* Advance to the next element. */
594 /* Advance to the next source element. */
596 while (count
[n
] == extent
[n
])
598 /* When we get to the end of a dimension, reset it and increment
599 the next dimension. */
601 /* We could precalculate these products, but this is a less
602 frequently used path so probably not worth it. */
603 dest
-= stride
[n
] * extent
[n
];
619 /* prefix(random_seed) is used to seed the PRNG with either a default
620 set of seeds or user specified set of seed. prefix(random_seed)
621 must be called with no argument or exactly one argument. */
624 random_seed (GFC_INTEGER_4
*size
, gfc_array_i4
* put
,
630 if (size
== NULL
&& put
== NULL
&& get
== NULL
)
632 /* From the standard: "If no argument is present, the processor assigns
633 a processor-dependent value to the seed." */
634 kiss_seed
[0] = kiss_default_seed
[0];
635 kiss_seed
[1] = kiss_default_seed
[1];
636 kiss_seed
[2] = kiss_default_seed
[2];
637 kiss_seed
[3] = kiss_default_seed
[3];
645 /* If the rank of the array is not 1, abort */
646 if (GFC_DESCRIPTOR_RANK (put
) != 1)
647 runtime_error ("Array rank of PUT is not 1.");
649 /* If the array is too small, abort */
650 if (((put
->dim
[0].ubound
+ 1 - put
->dim
[0].lbound
)) < kiss_size
)
651 runtime_error ("Array size of PUT is too small.");
653 if (put
->dim
[0].stride
== 0)
654 put
->dim
[0].stride
= 1;
656 /* This code now should do correct strides. */
657 for (i
= 0; i
< kiss_size
; i
++)
658 kiss_seed
[i
] =(GFC_UINTEGER_4
) put
->data
[i
* put
->dim
[0].stride
];
661 /* Return the seed to GET data */
664 /* If the rank of the array is not 1, abort. */
665 if (GFC_DESCRIPTOR_RANK (get
) != 1)
666 runtime_error ("Array rank of GET is not 1.");
668 /* If the array is too small, abort. */
669 if (((get
->dim
[0].ubound
+ 1 - get
->dim
[0].lbound
)) < kiss_size
)
670 runtime_error ("Array size of GET is too small.");
672 if (get
->dim
[0].stride
== 0)
673 get
->dim
[0].stride
= 1;
675 /* This code now should do correct strides. */
676 for (i
= 0; i
< kiss_size
; i
++)
677 get
->data
[i
* get
->dim
[0].stride
] = (GFC_INTEGER_4
) kiss_seed
[i
];