srfi-27.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. /* 54-BIT (double) IMPLEMENTATION IN C OF THE "MRG32K3A" GENERATOR
  2. ===============================================================
  3. Sebastian.Egner@philips.com, Mar-2002, in ANSI-C and Scheme 48 0.57
  4. This code is a C-implementation of Pierre L'Ecuyer's MRG32k3a generator.
  5. The code uses (double)-arithmetics, assuming that it covers the range
  6. {-2^53..2^53-1} exactly (!). The code of the generator is based on the
  7. L'Ecuyer's own implementation of the generator. Please refer to the
  8. file 'mrg32k3a.scm' for more information about the method.
  9. The method provides the following functions via the C/Scheme
  10. interface of Scheme 48 0.57 to 'mrg32k3a-b.scm':
  11. s48_ref_t mrg32k3a_pack_state1(s48_ref_t state);
  12. s48_ref_t mrg32k3a_unpack_state1(s48_ref_t state);
  13. s48_ref_t mrg32k3a_random_range();
  14. s48_ref_t mrg32k3a_random_integer(s48_ref_t state, s48_ref_t range);
  15. s48_ref_t mrg32k3a_random_real(s48_ref_t state);
  16. As Scheme48 FIXNUMs cannot cover the range {0..m1-1}, we break up
  17. all values x in the state into x0+x1*w, where w = 2^16 = 65536.
  18. The procedures in Scheme correct for that.
  19. compile this file with:
  20. gcc -c -I $SCHEME48 mrg32k3a-b.c
  21. history of this file:
  22. SE, 18-Mar-2002: initial version
  23. SE, 22-Mar-2002: interface changed
  24. SE, 25-Mar-2002: tested with Scheme 48 0.57 in c/srfi-27
  25. SE, 27-Mar-2002: cleaned
  26. SE, 13-May-2002: bug found by Shiro Kawai removed
  27. */
  28. #include "scheme48.h" /* $SCHEME48/c/scheme48.h */
  29. #ifdef _WIN32
  30. #include <windows.h>
  31. #else
  32. #include <sys/time.h>
  33. #endif
  34. #ifndef NULL
  35. #define NULL 0
  36. #endif
  37. /* maximum value for random_integer: min(S48_MAX_FIXNUM_VALUE, m1) */
  38. #define m_max (((long)1 << 29) - 1)
  39. /* The Generator
  40. =============
  41. */
  42. /* moduli of the components */
  43. #define m1 4294967087.0
  44. #define m2 4294944443.0
  45. /* representation of the state in C */
  46. typedef struct {
  47. double
  48. x10, x11, x12,
  49. x20, x21, x22;
  50. } state_t;
  51. /* recursion coefficients of the components */
  52. #define a12 1403580.0
  53. #define a13n 810728.0
  54. #define a21 527612.0
  55. #define a23n 1370589.0
  56. /* normalization factor 1/(m1 + 1) */
  57. #define norm 2.328306549295728e-10
  58. /* the actual generator */
  59. static double mrg32k3a(state_t *s) { /* (double), in {0..m1-1} */
  60. double x10, x20, y;
  61. long k10, k20;
  62. /* #define debug 1 */
  63. #if defined(debug)
  64. printf(
  65. "state = {%g %g %g %g %g %g};\n",
  66. s->x10, s->x11, s->x12,
  67. s->x20, s->x21, s->x22
  68. );
  69. #endif
  70. /* component 1 */
  71. x10 = a12*(s->x11) - a13n*(s->x12);
  72. k10 = x10 / m1;
  73. x10 -= k10 * m1;
  74. if (x10 < 0.0)
  75. x10 += m1;
  76. s->x12 = s->x11;
  77. s->x11 = s->x10;
  78. s->x10 = x10;
  79. /* component 2 */
  80. x20 = a21*(s->x20) - a23n*(s->x22);
  81. k20 = x20 / m2;
  82. x20 -= k20 * m2;
  83. if (x20 < 0.0)
  84. x20 += m2;
  85. s->x22 = s->x21;
  86. s->x21 = s->x20;
  87. s->x20 = x20;
  88. /* combination of component */
  89. y = x10 - x20;
  90. if (y < 0.0)
  91. y += m1;
  92. return y;
  93. }
  94. /* Exported Interface
  95. ==================
  96. */
  97. s48_ref_t mrg32k3a_pack_state1(s48_call_t call, s48_ref_t state) {
  98. s48_ref_t result;
  99. state_t s;
  100. #define REF(i) (double)s48_extract_long_2(call, s48_vector_ref_2(call, state, (long)(i)))
  101. /* copy the numbers from state into s */
  102. s.x10 = REF( 0) + 65536.0 * REF( 1);
  103. s.x11 = REF( 2) + 65536.0 * REF( 3);
  104. s.x12 = REF( 4) + 65536.0 * REF( 5);
  105. s.x20 = REF( 6) + 65536.0 * REF( 7);
  106. s.x21 = REF( 8) + 65536.0 * REF( 9);
  107. s.x22 = REF(10) + 65536.0 * REF(11);
  108. #undef REF
  109. /* box s into a Scheme object */
  110. result = s48_make_value_2(call, state_t);
  111. s48_set_value_2(call, result, state_t, s);
  112. return result;
  113. }
  114. s48_ref_t mrg32k3a_unpack_state1(s48_call_t call, s48_ref_t state) {
  115. s48_ref_t result;
  116. state_t s;
  117. /* unbox s from the Scheme object */
  118. s = s48_extract_value_2(call, state, state_t);
  119. /* make and fill a Scheme vector with the numbers */
  120. result = s48_make_vector_2(call, (long)12, s48_false_2(call));
  121. #define SET(i, x) { \
  122. long x1 = (long)((x) / 65536.0); \
  123. long x0 = (long)((x) - 65536.0 * (double)x1); \
  124. s48_vector_set_2(call, result, (long)(i+0), s48_enter_long_2(call, x0)); \
  125. s48_vector_set_2(call, result, (long)(i+1), s48_enter_long_2(call, x1)); }
  126. SET( 0, s.x10);
  127. SET( 2, s.x11);
  128. SET( 4, s.x12);
  129. SET( 6, s.x20);
  130. SET( 8, s.x21);
  131. SET(10, s.x22);
  132. #undef SET
  133. return result;
  134. }
  135. s48_ref_t mrg32k3a_random_range(s48_call_t call) {
  136. return s48_enter_long_2(call, m_max);
  137. }
  138. s48_ref_t mrg32k3a_random_integer(s48_call_t call, s48_ref_t state, s48_ref_t range) {
  139. long result;
  140. state_t s;
  141. long n;
  142. double x, q, qn, xq;
  143. s = s48_extract_value_2(call, state, state_t);
  144. n = s48_extract_long_2(call, range);
  145. if (!( ((long)1 <= n) && (n <= m_max) ))
  146. s48_assertion_violation_2(call, "mrg32k3a_random_integer", "invalid range", 1, state);
  147. /* generate result in {0..n-1} using the rejection method */
  148. q = (double)( (unsigned long)(m1 / (double)n) );
  149. qn = q * n;
  150. do {
  151. x = mrg32k3a(&s);
  152. } while (x >= qn);
  153. xq = x / q;
  154. /* check the range */
  155. if (!( (0.0 <= xq) && (xq < (double)m_max) ))
  156. s48_assertion_violation_2(call, "mrg32k3a_random_integer", "invalid xq", 1, s48_enter_long_2(call, (long)xq));
  157. /* return result */
  158. result = (long)xq;
  159. s48_set_value_2(call, state, state_t, s);
  160. return s48_enter_long_2(call, result);
  161. }
  162. s48_ref_t mrg32k3a_random_real(s48_call_t call, s48_ref_t state) {
  163. state_t s;
  164. double x;
  165. s = s48_extract_value_2(call, state, state_t);
  166. x = (mrg32k3a(&s) + 1.0) * norm;
  167. s48_set_value_2(call, state, state_t, s);
  168. return s48_enter_double_2(call, x);
  169. }
  170. #ifdef _WIN32
  171. static s48_ref_t current_time(s48_call_t call){
  172. SYSTEMTIME systemTime;
  173. GetSystemTime(&systemTime);
  174. return s48_enter_unsigned_long_2(call, (unsigned long) systemTime.wSecond);
  175. }
  176. #else
  177. static s48_ref_t current_time(s48_call_t call){
  178. struct timeval tv;
  179. gettimeofday(&tv, NULL);
  180. return s48_enter_long_2(call, tv.tv_sec);
  181. }
  182. #endif
  183. /* Exporting the C values to Scheme
  184. ================================
  185. */
  186. void
  187. s48_on_load(void) {
  188. S48_EXPORT_FUNCTION(mrg32k3a_pack_state1);
  189. S48_EXPORT_FUNCTION(mrg32k3a_unpack_state1);
  190. S48_EXPORT_FUNCTION(mrg32k3a_random_range);
  191. S48_EXPORT_FUNCTION(mrg32k3a_random_integer);
  192. S48_EXPORT_FUNCTION(mrg32k3a_random_real);
  193. S48_EXPORT_FUNCTION(current_time);
  194. }