gsl_rng__uni.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. /* rng/uni.c
  2. *
  3. * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 James Theiler, Brian Gough
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 3 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. */
  19. /**
  20. This is a lagged Fibonacci generator which supposedly excellent
  21. statistical properties (I do not concur)
  22. I got it from the net and translated into C.
  23. * ======================================================================
  24. * NIST Guide to Available Math Software.
  25. * Fullsource for module UNI from package CMLIB.
  26. * Retrieved from CAMSUN on Tue Oct 8 14:04:10 1996.
  27. * ======================================================================
  28. C***BEGIN PROLOGUE UNI
  29. C***DATE WRITTEN 810915
  30. C***REVISION DATE 830805
  31. C***CATEGORY NO. L6A21
  32. C***KEYWORDS RANDOM NUMBERS, UNIFORM RANDOM NUMBERS
  33. C***AUTHOR BLUE, JAMES, SCIENTIFIC COMPUTING DIVISION, NBS
  34. C KAHANER, DAVID, SCIENTIFIC COMPUTING DIVISION, NBS
  35. C MARSAGLIA, GEORGE, COMPUTER SCIENCE DEPT., WASH STATE UNIV
  36. C
  37. C***PURPOSE THIS ROUTINE GENERATES QUASI UNIFORM RANDOM NUMBERS ON [0,1
  38. C AND CAN BE USED ON ANY COMPUTER WITH WHICH ALLOWS INTEGERS
  39. C AT LEAST AS LARGE AS 32767.
  40. C***DESCRIPTION
  41. C
  42. C THIS ROUTINE GENERATES QUASI UNIFORM RANDOM NUMBERS ON THE INTER
  43. C [0,1). IT CAN BE USED WITH ANY COMPUTER WHICH ALLOWS
  44. C INTEGERS AT LEAST AS LARGE AS 32767.
  45. C
  46. C
  47. C USE
  48. C FIRST TIME....
  49. C Z = UNI(JD)
  50. C HERE JD IS ANY N O N - Z E R O INTEGER.
  51. C THIS CAUSES INITIALIZATION OF THE PROGRAM
  52. C AND THE FIRST RANDOM NUMBER TO BE RETURNED AS Z.
  53. C SUBSEQUENT TIMES...
  54. C Z = UNI(0)
  55. C CAUSES THE NEXT RANDOM NUMBER TO BE RETURNED AS Z.
  56. C
  57. C
  58. C..................................................................
  59. C NOTE: USERS WHO WISH TO TRANSPORT THIS PROGRAM FROM ONE COMPUTER
  60. C TO ANOTHER SHOULD READ THE FOLLOWING INFORMATION.....
  61. C
  62. C MACHINE DEPENDENCIES...
  63. C MDIG = A LOWER BOUND ON THE NUMBER OF BINARY DIGITS AVAILABLE
  64. C FOR REPRESENTING INTEGERS, INCLUDING THE SIGN BIT.
  65. C THIS VALUE MUST BE AT LEAST 16, BUT MAY BE INCREASED
  66. C IN LINE WITH REMARK A BELOW.
  67. C
  68. C REMARKS...
  69. C A. THIS PROGRAM CAN BE USED IN TWO WAYS:
  70. C (1) TO OBTAIN REPEATABLE RESULTS ON DIFFERENT COMPUTERS,
  71. C SET 'MDIG' TO THE SMALLEST OF ITS VALUES ON EACH, OR,
  72. C (2) TO ALLOW THE LONGEST SEQUENCE OF RANDOM NUMBERS TO BE
  73. C GENERATED WITHOUT CYCLING (REPEATING) SET 'MDIG' TO THE
  74. C LARGEST POSSIBLE VALUE.
  75. C B. THE SEQUENCE OF NUMBERS GENERATED DEPENDS ON THE INITIAL
  76. C INPUT 'JD' AS WELL AS THE VALUE OF 'MDIG'.
  77. C IF MDIG=16 ONE SHOULD FIND THAT
  78. Editors Note: set the seed using 152 in order to get uni(305)
  79. -jt
  80. C THE FIRST EVALUATION
  81. C Z=UNI(305) GIVES Z=.027832881...
  82. C THE SECOND EVALUATION
  83. C Z=UNI(0) GIVES Z=.56102176...
  84. C THE THIRD EVALUATION
  85. C Z=UNI(0) GIVES Z=.41456343...
  86. C THE THOUSANDTH EVALUATION
  87. C Z=UNI(0) GIVES Z=.19797357...
  88. C
  89. C***REFERENCES MARSAGLIA G., "COMMENTS ON THE PERFECT UNIFORM RANDOM
  90. C NUMBER GENERATOR", UNPUBLISHED NOTES, WASH S. U.
  91. C***ROUTINES CALLED I1MACH,XERROR
  92. C***END PROLOGUE UNI
  93. **/
  94. #include "gsl__config.h"
  95. #include <stdlib.h>
  96. #include "gsl_rng.h"
  97. static inline unsigned long int uni_get (void *vstate);
  98. static double uni_get_double (void *vstate);
  99. static void uni_set (void *state, unsigned long int s);
  100. static const unsigned int MDIG = 16; /* Machine digits in int */
  101. static const unsigned int m1 = 32767; /* 2^(MDIG-1) - 1 */
  102. static const unsigned int m2 = 256; /* 2^(MDIG/2) */
  103. typedef struct
  104. {
  105. int i, j;
  106. unsigned long m[17];
  107. }
  108. uni_state_t;
  109. static inline unsigned long
  110. uni_get (void *vstate)
  111. {
  112. uni_state_t *state = (uni_state_t *) vstate;
  113. const int i = state->i;
  114. const int j = state->j;
  115. /* important k not be unsigned */
  116. long k = state->m[i] - state->m[j];
  117. if (k < 0)
  118. k += m1;
  119. state->m[j] = k;
  120. if (i == 0)
  121. {
  122. state->i = 16;
  123. }
  124. else
  125. {
  126. (state->i)--;
  127. }
  128. if (j == 0)
  129. {
  130. state->j = 16;
  131. }
  132. else
  133. {
  134. (state->j)--;
  135. }
  136. return k;
  137. }
  138. static double
  139. uni_get_double (void *vstate)
  140. {
  141. return uni_get (vstate) / 32767.0 ;
  142. }
  143. static void
  144. uni_set (void *vstate, unsigned long int s)
  145. {
  146. unsigned int i, seed, k0, k1, j0, j1;
  147. uni_state_t *state = (uni_state_t *) vstate;
  148. /* For this routine, the seeding is very elaborate! */
  149. /* A flaw in this approach is that seeds 1,2 give exactly the
  150. same random number sequence! */
  151. s = 2 * s + 1; /* enforce seed be odd */
  152. seed = (s < m1 ? s : m1); /* seed should be less than m1 */
  153. k0 = 9069 % m2;
  154. k1 = 9069 / m2;
  155. j0 = seed % m2;
  156. j1 = seed / m2;
  157. for (i = 0; i < 17; ++i)
  158. {
  159. seed = j0 * k0;
  160. j1 = (seed / m2 + j0 * k1 + j1 * k0) % (m2 / 2);
  161. j0 = seed % m2;
  162. state->m[i] = j0 + m2 * j1;
  163. }
  164. state->i = 4;
  165. state->j = 16;
  166. return;
  167. }
  168. static const gsl_rng_type uni_type =
  169. {"uni", /* name */
  170. 32766, /* RAND_MAX */
  171. 0, /* RAND_MIN */
  172. sizeof (uni_state_t),
  173. &uni_set,
  174. &uni_get,
  175. &uni_get_double};
  176. const gsl_rng_type *gsl_rng_uni = &uni_type;