random.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. /*
  2. * C version of Marsaglia's UNI random number generator
  3. * More or less transliterated from the Fortran -- with 1 bug fix
  4. * Hence horrible style
  5. *
  6. * Features:
  7. * ANSI C
  8. * not callable from Fortran (yet)
  9. */
  10. char uni_id[] = "$Id: random.c,v 1.7 2009/08/28 09:09:17 spb Exp $" ;
  11. /*
  12. * Global variables for rstart & uni
  13. */
  14. #define PARANOID
  15. /* need types and time */
  16. #include <X11/Xos.h>
  17. /* #include <sys/types.h>
  18. * #include <sys/time.h>
  19. */
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <math.h>
  23. typedef struct
  24. {
  25. float u[98];
  26. float c;
  27. float cd;
  28. float cm;
  29. int ui;
  30. int uj;
  31. }
  32. Uni_save;
  33. Uni_save uni_data;
  34. float uni()
  35. {
  36. float luni; /* local variable for uni */
  37. luni = uni_data.u[uni_data.ui] - uni_data.u[uni_data.uj];
  38. if (luni < 0.0)
  39. luni += 1.0;
  40. uni_data.u[uni_data.ui] = luni;
  41. if (--uni_data.ui == 0)
  42. uni_data.ui = 97;
  43. if (--uni_data.uj == 0)
  44. uni_data.uj = 97;
  45. if ((uni_data.c -= uni_data.cd) < 0.0)
  46. uni_data.c += uni_data.cm;
  47. if ((luni -= uni_data.c) < 0.0)
  48. luni += 1.0;
  49. return ((float) luni);
  50. }
  51. void rstart(i,j,k,l)
  52. int i;
  53. int j;
  54. int k;
  55. int l;
  56. {
  57. int ii, jj, m;
  58. float s, t;
  59. for (ii = 1; ii <= 97; ii++) {
  60. s = 0.0;
  61. t = 0.5;
  62. for (jj = 1; jj <= 24; jj++) {
  63. m = ((i*j % 179) * k) % 179;
  64. i = j;
  65. j = k;
  66. k = m;
  67. l = (53*l+1) % 169;
  68. if (l*m % 64 >= 32)
  69. s += t;
  70. t *= 0.5;
  71. }
  72. uni_data.u[ii] = s;
  73. }
  74. uni_data.c = 362436.0 / 16777216.0;
  75. uni_data.cd = 7654321.0 / 16777216.0;
  76. uni_data.cm = 16777213.0 / 16777216.0;
  77. uni_data.ui = 97; /* There is a bug in the original Fortran version */
  78. uni_data.uj = 33; /* of UNI -- i and j should be SAVEd in UNI() */
  79. }
  80. /* ~seed_uni: this takes a single integer in the range
  81. * 0 <= ijkl <= 900 000 000
  82. * and produces the four smaller integers needed for rstart. It is
  83. * based on the ideas contained in the RMARIN subroutine in
  84. * F. James, "A Review of Pseudorandom Number Generators",
  85. * Comp. Phys. Commun. Oct 1990, p.340
  86. * To reduce the modifications to the existing code, seed_uni now
  87. * takes the role of a preprocessor for rstart.
  88. *
  89. */
  90. void seed_uni(ijkl)
  91. int ijkl;
  92. {
  93. int i, j, k, l, ij, kl;
  94. if( ijkl == 0 )
  95. {
  96. ijkl = time((time_t *) 0);
  97. ijkl %= 900000000;
  98. }
  99. /* check ijkl is within range */
  100. if( (ijkl < 0) || (ijkl > 900000000) )
  101. {
  102. fprintf(stderr,"seed_uni: ijkl = %d -- out of range\n\n", ijkl);
  103. exit(3);
  104. }
  105. /* decompose the long integer into the the equivalent four
  106. * integers for rstart. This should be a 1-1 mapping
  107. * ijkl <--> (i, j, k, l)
  108. * though not quite all of the possible sets of (i, j, k, l)
  109. * can be produced.
  110. */
  111. ij = ijkl/30082;
  112. kl = ijkl - (30082 * ij);
  113. i = ((ij/177) % 177) + 2;
  114. j = (ij % 177) + 2;
  115. k = ((kl/169) % 178) + 1;
  116. l = kl % 169;
  117. #ifdef PARANOID
  118. if( (i <= 0) || (i > 178) )
  119. {
  120. fprintf(stderr,"seed_uni: i = %d -- out of range\n\n", i);
  121. exit(3);
  122. }
  123. if( (j <= 0) || (j > 178) )
  124. {
  125. fprintf(stderr,"seed_uni: j = %d -- out of range\n\n", j);
  126. exit(3);
  127. }
  128. if( (k <= 0) || (k > 178) )
  129. {
  130. fprintf(stderr,"seed_uni: k = %d -- out of range\n\n", k);
  131. exit(3);
  132. }
  133. if( (l < 0) || (l > 168) )
  134. {
  135. fprintf(stderr,"seed_uni: l = %d -- out of range\n\n", l);
  136. exit(3);
  137. }
  138. if (i == 1 && j == 1 && k == 1)
  139. {
  140. fprintf(stderr,"seed_uni: 1 1 1 not allowed for 1st 3 seeds\n\n");
  141. exit(4);
  142. }
  143. #endif
  144. rstart(i, j, k, l);
  145. }
  146. float gaussian()
  147. {
  148. double pi = 3.1415926536, two = 2.0, zero = 0.0;
  149. double ran1, ran2;
  150. do {
  151. ran1 = (double) uni();
  152. } while (ran1 == zero);
  153. ran2 = (double) uni();
  154. return (float) ( sqrt(-two * log(ran1)) * cos(two * pi * ran2) );
  155. }