Update Gnulib to v0.0-6827-g39c3009; use the `dirfd' module.
[bpt/guile.git] / libguile / random.c
1 /* Copyright (C) 1999,2000,2001, 2003, 2005, 2006, 2009, 2010 Free Software Foundation, Inc.
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public License
4 * as published by the Free Software Foundation; either version 3 of
5 * the License, or (at your option) any later version.
6 *
7 * This library is distributed in the hope that it will be useful, but
8 * WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301 USA
16 */
17
18
19
20 /* Author: Mikael Djurfeldt <djurfeldt@nada.kth.se> */
21
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
25
26 #include "libguile/_scm.h"
27
28 #include <gmp.h>
29 #include <stdio.h>
30 #include <math.h>
31 #include <string.h>
32 #include "libguile/smob.h"
33 #include "libguile/numbers.h"
34 #include "libguile/feature.h"
35 #include "libguile/strings.h"
36 #include "libguile/arrays.h"
37 #include "libguile/srfi-4.h"
38 #include "libguile/vectors.h"
39 #include "libguile/generalized-vectors.h"
40
41 #include "libguile/validate.h"
42 #include "libguile/random.h"
43
44 \f
45 /*
46 * A plugin interface for RNGs
47 *
48 * Using this interface, it is possible for the application to tell
49 * libguile to use a different RNG. This is desirable if it is
50 * necessary to use the same RNG everywhere in the application in
51 * order to prevent interference, if the application uses RNG
52 * hardware, or if the application has special demands on the RNG.
53 *
54 * Look in random.h and how the default generator is "plugged in" in
55 * scm_init_random().
56 */
57
58 scm_t_rng scm_the_rng;
59
60 \f
61 /*
62 * The prepackaged RNG
63 *
64 * This is the MWC (Multiply With Carry) random number generator
65 * described by George Marsaglia at the Department of Statistics and
66 * Supercomputer Computations Research Institute, The Florida State
67 * University (http://stat.fsu.edu/~geo).
68 *
69 * It uses 64 bits, has a period of 4578426017172946943 (4.6e18), and
70 * passes all tests in the DIEHARD test suite
71 * (http://stat.fsu.edu/~geo/diehard.html)
72 */
73
74 typedef struct scm_t_i_rstate {
75 scm_t_rstate rstate;
76 scm_t_uint32 w;
77 scm_t_uint32 c;
78 } scm_t_i_rstate;
79
80
81 #define A 2131995753UL
82
83 #ifndef M_PI
84 #define M_PI 3.14159265359
85 #endif
86
87 static scm_t_uint32
88 scm_i_uniform32 (scm_t_rstate *state)
89 {
90 scm_t_i_rstate *istate = (scm_t_i_rstate*) state;
91 scm_t_uint64 x = (scm_t_uint64) A * istate->w + istate->c;
92 scm_t_uint32 w = x & 0xffffffffUL;
93 istate->w = w;
94 istate->c = x >> 32L;
95 return w;
96 }
97
98 static void
99 scm_i_init_rstate (scm_t_rstate *state, const char *seed, int n)
100 {
101 scm_t_i_rstate *istate = (scm_t_i_rstate*) state;
102 scm_t_uint32 w = 0L;
103 scm_t_uint32 c = 0L;
104 int i, m;
105 for (i = 0; i < n; ++i)
106 {
107 m = i % 8;
108 if (m < 4)
109 w += seed[i] << (8 * m);
110 else
111 c += seed[i] << (8 * (m - 4));
112 }
113 if ((w == 0 && c == 0) || (w == -1 && c == A - 1))
114 ++c;
115 istate->w = w;
116 istate->c = c;
117 }
118
119 static scm_t_rstate *
120 scm_i_copy_rstate (scm_t_rstate *state)
121 {
122 scm_t_rstate *new_state;
123
124 new_state = scm_gc_malloc_pointerless (state->rng->rstate_size,
125 "random-state");
126 return memcpy (new_state, state, state->rng->rstate_size);
127 }
128
129 SCM_SYMBOL(scm_i_rstate_tag, "multiply-with-carry");
130
131 static void
132 scm_i_rstate_from_datum (scm_t_rstate *state, SCM value)
133 #define FUNC_NAME "scm_i_rstate_from_datum"
134 {
135 scm_t_i_rstate *istate = (scm_t_i_rstate*) state;
136 scm_t_uint32 w, c;
137 long length;
138
139 SCM_VALIDATE_LIST_COPYLEN (SCM_ARG1, value, length);
140 SCM_ASSERT (length == 3, value, SCM_ARG1, FUNC_NAME);
141 SCM_ASSERT (scm_is_eq (SCM_CAR (value), scm_i_rstate_tag),
142 value, SCM_ARG1, FUNC_NAME);
143 SCM_VALIDATE_UINT_COPY (SCM_ARG1, SCM_CADR (value), w);
144 SCM_VALIDATE_UINT_COPY (SCM_ARG1, SCM_CADDR (value), c);
145
146 istate->w = w;
147 istate->c = c;
148 }
149 #undef FUNC_NAME
150
151 static SCM
152 scm_i_rstate_to_datum (scm_t_rstate *state)
153 {
154 scm_t_i_rstate *istate = (scm_t_i_rstate*) state;
155 return scm_list_3 (scm_i_rstate_tag,
156 scm_from_uint32 (istate->w),
157 scm_from_uint32 (istate->c));
158 }
159
160 \f
161 /*
162 * Random number library functions
163 */
164
165 scm_t_rstate *
166 scm_c_make_rstate (const char *seed, int n)
167 {
168 scm_t_rstate *state;
169
170 state = scm_gc_malloc_pointerless (scm_the_rng.rstate_size,
171 "random-state");
172 state->rng = &scm_the_rng;
173 state->normal_next = 0.0;
174 state->rng->init_rstate (state, seed, n);
175 return state;
176 }
177
178 scm_t_rstate *
179 scm_c_rstate_from_datum (SCM datum)
180 {
181 scm_t_rstate *state;
182
183 state = scm_gc_malloc_pointerless (scm_the_rng.rstate_size,
184 "random-state");
185 state->rng = &scm_the_rng;
186 state->normal_next = 0.0;
187 state->rng->from_datum (state, datum);
188 return state;
189 }
190
191 scm_t_rstate *
192 scm_c_default_rstate ()
193 #define FUNC_NAME "scm_c_default_rstate"
194 {
195 SCM state = SCM_VARIABLE_REF (scm_var_random_state);
196 if (!SCM_RSTATEP (state))
197 SCM_MISC_ERROR ("*random-state* contains bogus random state", SCM_EOL);
198 return SCM_RSTATE (state);
199 }
200 #undef FUNC_NAME
201
202
203 double
204 scm_c_uniform01 (scm_t_rstate *state)
205 {
206 double x = (double) state->rng->random_bits (state) / (double) 0xffffffffUL;
207 return ((x + (double) state->rng->random_bits (state))
208 / (double) 0xffffffffUL);
209 }
210
211 double
212 scm_c_normal01 (scm_t_rstate *state)
213 {
214 if (state->normal_next != 0.0)
215 {
216 double ret = state->normal_next;
217
218 state->normal_next = 0.0;
219
220 return ret;
221 }
222 else
223 {
224 double r, a, n;
225
226 r = sqrt (-2.0 * log (scm_c_uniform01 (state)));
227 a = 2.0 * M_PI * scm_c_uniform01 (state);
228
229 n = r * sin (a);
230 state->normal_next = r * cos (a);
231
232 return n;
233 }
234 }
235
236 double
237 scm_c_exp1 (scm_t_rstate *state)
238 {
239 return - log (scm_c_uniform01 (state));
240 }
241
242 unsigned char scm_masktab[256];
243
244 static inline scm_t_uint32
245 scm_i_mask32 (scm_t_uint32 m)
246 {
247 return (m < 0x100
248 ? scm_masktab[m]
249 : (m < 0x10000
250 ? scm_masktab[m >> 8] << 8 | 0xff
251 : (m < 0x1000000
252 ? scm_masktab[m >> 16] << 16 | 0xffff
253 : scm_masktab[m >> 24] << 24 | 0xffffff)));
254 }
255
256 scm_t_uint32
257 scm_c_random (scm_t_rstate *state, scm_t_uint32 m)
258 {
259 scm_t_uint32 r, mask = scm_i_mask32 (m);
260 while ((r = state->rng->random_bits (state) & mask) >= m);
261 return r;
262 }
263
264 scm_t_uint64
265 scm_c_random64 (scm_t_rstate *state, scm_t_uint64 m)
266 {
267 scm_t_uint64 r;
268 scm_t_uint32 mask;
269
270 if (m <= SCM_T_UINT32_MAX)
271 return scm_c_random (state, (scm_t_uint32) m);
272
273 mask = scm_i_mask32 (m >> 32);
274 while ((r = ((scm_t_uint64) (state->rng->random_bits (state) & mask) << 32)
275 | state->rng->random_bits (state)) >= m)
276 ;
277 return r;
278 }
279
280 /*
281 SCM scm_c_random_bignum (scm_t_rstate *state, SCM m)
282
283 Takes a random state (source of random bits) and a bignum m.
284 Returns a bignum b, 0 <= b < m.
285
286 It does this by allocating a bignum b with as many base 65536 digits
287 as m, filling b with random bits (in 32 bit chunks) up to the most
288 significant 1 in m, and, finally checking if the resultant b is too
289 large (>= m). If too large, we simply repeat the process again. (It
290 is important to throw away all generated random bits if b >= m,
291 otherwise we'll end up with a distorted distribution.)
292
293 */
294
295 SCM
296 scm_c_random_bignum (scm_t_rstate *state, SCM m)
297 {
298 SCM result = scm_i_mkbig ();
299 const size_t m_bits = mpz_sizeinbase (SCM_I_BIG_MPZ (m), 2);
300 /* how many bits would only partially fill the last scm_t_uint32? */
301 const size_t end_bits = m_bits % (sizeof (scm_t_uint32) * SCM_CHAR_BIT);
302 scm_t_uint32 *random_chunks = NULL;
303 const scm_t_uint32 num_full_chunks =
304 m_bits / (sizeof (scm_t_uint32) * SCM_CHAR_BIT);
305 const scm_t_uint32 num_chunks = num_full_chunks + ((end_bits) ? 1 : 0);
306
307 /* we know the result will be this big */
308 mpz_realloc2 (SCM_I_BIG_MPZ (result), m_bits);
309
310 random_chunks =
311 (scm_t_uint32 *) scm_gc_calloc (num_chunks * sizeof (scm_t_uint32),
312 "random bignum chunks");
313
314 do
315 {
316 scm_t_uint32 *current_chunk = random_chunks + (num_chunks - 1);
317 scm_t_uint32 chunks_left = num_chunks;
318
319 mpz_set_ui (SCM_I_BIG_MPZ (result), 0);
320
321 if (end_bits)
322 {
323 /* generate a mask with ones in the end_bits position, i.e. if
324 end_bits is 3, then we'd have a mask of ...0000000111 */
325 const scm_t_uint32 rndbits = state->rng->random_bits (state);
326 int rshift = (sizeof (scm_t_uint32) * SCM_CHAR_BIT) - end_bits;
327 scm_t_uint32 mask = ((scm_t_uint32)-1) >> rshift;
328 scm_t_uint32 highest_bits = rndbits & mask;
329 *current_chunk-- = highest_bits;
330 chunks_left--;
331 }
332
333 while (chunks_left)
334 {
335 /* now fill in the remaining scm_t_uint32 sized chunks */
336 *current_chunk-- = state->rng->random_bits (state);
337 chunks_left--;
338 }
339 mpz_import (SCM_I_BIG_MPZ (result),
340 num_chunks,
341 -1,
342 sizeof (scm_t_uint32),
343 0,
344 0,
345 random_chunks);
346 /* if result >= m, regenerate it (it is important to regenerate
347 all bits in order not to get a distorted distribution) */
348 } while (mpz_cmp (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (m)) >= 0);
349 scm_gc_free (random_chunks,
350 num_chunks * sizeof (scm_t_uint32),
351 "random bignum chunks");
352 return scm_i_normbig (result);
353 }
354
355 /*
356 * Scheme level representation of random states.
357 */
358
359 scm_t_bits scm_tc16_rstate;
360
361 static SCM
362 make_rstate (scm_t_rstate *state)
363 {
364 SCM_RETURN_NEWSMOB (scm_tc16_rstate, state);
365 }
366
367
368 /*
369 * Scheme level interface.
370 */
371
372 SCM_GLOBAL_VARIABLE_INIT (scm_var_random_state, "*random-state*", scm_seed_to_random_state (scm_from_locale_string ("URL:http://stat.fsu.edu/~geo/diehard.html")));
373
374 SCM_DEFINE (scm_random, "random", 1, 1, 0,
375 (SCM n, SCM state),
376 "Return a number in [0, N).\n"
377 "\n"
378 "Accepts a positive integer or real n and returns a\n"
379 "number of the same type between zero (inclusive) and\n"
380 "N (exclusive). The values returned have a uniform\n"
381 "distribution.\n"
382 "\n"
383 "The optional argument @var{state} must be of the type produced\n"
384 "by @code{seed->random-state}. It defaults to the value of the\n"
385 "variable @var{*random-state*}. This object is used to maintain\n"
386 "the state of the pseudo-random-number generator and is altered\n"
387 "as a side effect of the random operation.")
388 #define FUNC_NAME s_scm_random
389 {
390 if (SCM_UNBNDP (state))
391 state = SCM_VARIABLE_REF (scm_var_random_state);
392 SCM_VALIDATE_RSTATE (2, state);
393 if (SCM_I_INUMP (n))
394 {
395 scm_t_bits m = (scm_t_bits) SCM_I_INUM (n);
396 SCM_ASSERT_RANGE (1, n, SCM_I_INUM (n) > 0);
397 #if SCM_SIZEOF_UINTPTR_T <= 4
398 return scm_from_uint32 (scm_c_random (SCM_RSTATE (state),
399 (scm_t_uint32) m));
400 #elif SCM_SIZEOF_UINTPTR_T <= 8
401 return scm_from_uint64 (scm_c_random64 (SCM_RSTATE (state),
402 (scm_t_uint64) m));
403 #else
404 #error "Cannot deal with this platform's scm_t_bits size"
405 #endif
406 }
407 SCM_VALIDATE_NIM (1, n);
408 if (SCM_REALP (n))
409 return scm_from_double (SCM_REAL_VALUE (n)
410 * scm_c_uniform01 (SCM_RSTATE (state)));
411
412 if (!SCM_BIGP (n))
413 SCM_WRONG_TYPE_ARG (1, n);
414 return scm_c_random_bignum (SCM_RSTATE (state), n);
415 }
416 #undef FUNC_NAME
417
418 SCM_DEFINE (scm_copy_random_state, "copy-random-state", 0, 1, 0,
419 (SCM state),
420 "Return a copy of the random state @var{state}.")
421 #define FUNC_NAME s_scm_copy_random_state
422 {
423 if (SCM_UNBNDP (state))
424 state = SCM_VARIABLE_REF (scm_var_random_state);
425 SCM_VALIDATE_RSTATE (1, state);
426 return make_rstate (SCM_RSTATE (state)->rng->copy_rstate (SCM_RSTATE (state)));
427 }
428 #undef FUNC_NAME
429
430 SCM_DEFINE (scm_seed_to_random_state, "seed->random-state", 1, 0, 0,
431 (SCM seed),
432 "Return a new random state using @var{seed}.")
433 #define FUNC_NAME s_scm_seed_to_random_state
434 {
435 SCM res;
436 if (SCM_NUMBERP (seed))
437 seed = scm_number_to_string (seed, SCM_UNDEFINED);
438 SCM_VALIDATE_STRING (1, seed);
439 res = make_rstate (scm_c_make_rstate (scm_i_string_chars (seed),
440 scm_i_string_length (seed)));
441 scm_remember_upto_here_1 (seed);
442 return res;
443
444 }
445 #undef FUNC_NAME
446
447 SCM_DEFINE (scm_datum_to_random_state, "datum->random-state", 1, 0, 0,
448 (SCM datum),
449 "Return a new random state using @var{datum}, which should have\n"
450 "been obtained from @code{random-state->datum}.")
451 #define FUNC_NAME s_scm_datum_to_random_state
452 {
453 return make_rstate (scm_c_rstate_from_datum (datum));
454 }
455 #undef FUNC_NAME
456
457 SCM_DEFINE (scm_random_state_to_datum, "random-state->datum", 1, 0, 0,
458 (SCM state),
459 "Return a datum representation of @var{state} that may be\n"
460 "written out and read back with the Scheme reader.")
461 #define FUNC_NAME s_scm_random_state_to_datum
462 {
463 SCM_VALIDATE_RSTATE (1, state);
464 return SCM_RSTATE (state)->rng->to_datum (SCM_RSTATE (state));
465 }
466 #undef FUNC_NAME
467
468 SCM_DEFINE (scm_random_uniform, "random:uniform", 0, 1, 0,
469 (SCM state),
470 "Return a uniformly distributed inexact real random number in\n"
471 "[0,1).")
472 #define FUNC_NAME s_scm_random_uniform
473 {
474 if (SCM_UNBNDP (state))
475 state = SCM_VARIABLE_REF (scm_var_random_state);
476 SCM_VALIDATE_RSTATE (1, state);
477 return scm_from_double (scm_c_uniform01 (SCM_RSTATE (state)));
478 }
479 #undef FUNC_NAME
480
481 SCM_DEFINE (scm_random_normal, "random:normal", 0, 1, 0,
482 (SCM state),
483 "Return an inexact real in a normal distribution. The\n"
484 "distribution used has mean 0 and standard deviation 1. For a\n"
485 "normal distribution with mean m and standard deviation d use\n"
486 "@code{(+ m (* d (random:normal)))}.")
487 #define FUNC_NAME s_scm_random_normal
488 {
489 if (SCM_UNBNDP (state))
490 state = SCM_VARIABLE_REF (scm_var_random_state);
491 SCM_VALIDATE_RSTATE (1, state);
492 return scm_from_double (scm_c_normal01 (SCM_RSTATE (state)));
493 }
494 #undef FUNC_NAME
495
496 static void
497 vector_scale_x (SCM v, double c)
498 {
499 size_t n;
500 if (scm_is_simple_vector (v))
501 {
502 n = SCM_SIMPLE_VECTOR_LENGTH (v);
503 while (n-- > 0)
504 SCM_REAL_VALUE (SCM_SIMPLE_VECTOR_REF (v, n)) *= c;
505 }
506 else
507 {
508 /* must be a f64vector. */
509 scm_t_array_handle handle;
510 size_t i, len;
511 ssize_t inc;
512 double *elts;
513
514 elts = scm_f64vector_writable_elements (v, &handle, &len, &inc);
515
516 for (i = 0; i < len; i++, elts += inc)
517 *elts *= c;
518
519 scm_array_handle_release (&handle);
520 }
521 }
522
523 static double
524 vector_sum_squares (SCM v)
525 {
526 double x, sum = 0.0;
527 size_t n;
528 if (scm_is_simple_vector (v))
529 {
530 n = SCM_SIMPLE_VECTOR_LENGTH (v);
531 while (n-- > 0)
532 {
533 x = SCM_REAL_VALUE (SCM_SIMPLE_VECTOR_REF (v, n));
534 sum += x * x;
535 }
536 }
537 else
538 {
539 /* must be a f64vector. */
540 scm_t_array_handle handle;
541 size_t i, len;
542 ssize_t inc;
543 const double *elts;
544
545 elts = scm_f64vector_elements (v, &handle, &len, &inc);
546
547 for (i = 0; i < len; i++, elts += inc)
548 {
549 x = *elts;
550 sum += x * x;
551 }
552
553 scm_array_handle_release (&handle);
554 }
555 return sum;
556 }
557
558 /* For the uniform distribution on the solid sphere, note that in
559 * this distribution the length r of the vector has cumulative
560 * distribution r^n; i.e., u=r^n is uniform [0,1], so r can be
561 * generated as r=u^(1/n).
562 */
563 SCM_DEFINE (scm_random_solid_sphere_x, "random:solid-sphere!", 1, 1, 0,
564 (SCM v, SCM state),
565 "Fills @var{vect} with inexact real random numbers the sum of\n"
566 "whose squares is less than 1.0. Thinking of @var{vect} as\n"
567 "coordinates in space of dimension @var{n} @math{=}\n"
568 "@code{(vector-length @var{vect})}, the coordinates are\n"
569 "uniformly distributed within the unit @var{n}-sphere.")
570 #define FUNC_NAME s_scm_random_solid_sphere_x
571 {
572 if (SCM_UNBNDP (state))
573 state = SCM_VARIABLE_REF (scm_var_random_state);
574 SCM_VALIDATE_RSTATE (2, state);
575 scm_random_normal_vector_x (v, state);
576 vector_scale_x (v,
577 pow (scm_c_uniform01 (SCM_RSTATE (state)),
578 1.0 / scm_c_generalized_vector_length (v))
579 / sqrt (vector_sum_squares (v)));
580 return SCM_UNSPECIFIED;
581 }
582 #undef FUNC_NAME
583
584 SCM_DEFINE (scm_random_hollow_sphere_x, "random:hollow-sphere!", 1, 1, 0,
585 (SCM v, SCM state),
586 "Fills vect with inexact real random numbers\n"
587 "the sum of whose squares is equal to 1.0.\n"
588 "Thinking of vect as coordinates in space of\n"
589 "dimension n = (vector-length vect), the coordinates\n"
590 "are uniformly distributed over the surface of the\n"
591 "unit n-sphere.")
592 #define FUNC_NAME s_scm_random_hollow_sphere_x
593 {
594 if (SCM_UNBNDP (state))
595 state = SCM_VARIABLE_REF (scm_var_random_state);
596 SCM_VALIDATE_RSTATE (2, state);
597 scm_random_normal_vector_x (v, state);
598 vector_scale_x (v, 1 / sqrt (vector_sum_squares (v)));
599 return SCM_UNSPECIFIED;
600 }
601 #undef FUNC_NAME
602
603
604 SCM_DEFINE (scm_random_normal_vector_x, "random:normal-vector!", 1, 1, 0,
605 (SCM v, SCM state),
606 "Fills vect with inexact real random numbers that are\n"
607 "independent and standard normally distributed\n"
608 "(i.e., with mean 0 and variance 1).")
609 #define FUNC_NAME s_scm_random_normal_vector_x
610 {
611 long i;
612 scm_t_array_handle handle;
613 scm_t_array_dim *dim;
614
615 if (SCM_UNBNDP (state))
616 state = SCM_VARIABLE_REF (scm_var_random_state);
617 SCM_VALIDATE_RSTATE (2, state);
618
619 scm_generalized_vector_get_handle (v, &handle);
620 dim = scm_array_handle_dims (&handle);
621
622 if (scm_is_vector (v))
623 {
624 SCM *elts = scm_array_handle_writable_elements (&handle);
625 for (i = dim->lbnd; i <= dim->ubnd; i++, elts += dim->inc)
626 *elts = scm_from_double (scm_c_normal01 (SCM_RSTATE (state)));
627 }
628 else
629 {
630 /* must be a f64vector. */
631 double *elts = scm_array_handle_f64_writable_elements (&handle);
632 for (i = dim->lbnd; i <= dim->ubnd; i++, elts += dim->inc)
633 *elts = scm_c_normal01 (SCM_RSTATE (state));
634 }
635
636 scm_array_handle_release (&handle);
637
638 return SCM_UNSPECIFIED;
639 }
640 #undef FUNC_NAME
641
642 SCM_DEFINE (scm_random_exp, "random:exp", 0, 1, 0,
643 (SCM state),
644 "Return an inexact real in an exponential distribution with mean\n"
645 "1. For an exponential distribution with mean u use (* u\n"
646 "(random:exp)).")
647 #define FUNC_NAME s_scm_random_exp
648 {
649 if (SCM_UNBNDP (state))
650 state = SCM_VARIABLE_REF (scm_var_random_state);
651 SCM_VALIDATE_RSTATE (1, state);
652 return scm_from_double (scm_c_exp1 (SCM_RSTATE (state)));
653 }
654 #undef FUNC_NAME
655
656 void
657 scm_init_random ()
658 {
659 int i, m;
660 /* plug in default RNG */
661 scm_t_rng rng =
662 {
663 sizeof (scm_t_i_rstate),
664 scm_i_uniform32,
665 scm_i_init_rstate,
666 scm_i_copy_rstate,
667 scm_i_rstate_from_datum,
668 scm_i_rstate_to_datum
669 };
670 scm_the_rng = rng;
671
672 scm_tc16_rstate = scm_make_smob_type ("random-state", 0);
673
674 for (m = 1; m <= 0x100; m <<= 1)
675 for (i = m >> 1; i < m; ++i)
676 scm_masktab[i] = m - 1;
677
678 #include "libguile/random.x"
679
680 scm_add_feature ("random");
681 }
682
683 /*
684 Local Variables:
685 c-file-style: "gnu"
686 End:
687 */