64-bit random fixes
[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 scm_t_uint32
245 scm_c_random (scm_t_rstate *state, scm_t_uint32 m)
246 {
247 scm_t_uint32 r, mask;
248 mask = (m < 0x100
249 ? scm_masktab[m]
250 : (m < 0x10000
251 ? scm_masktab[m >> 8] << 8 | 0xff
252 : (m < 0x1000000
253 ? scm_masktab[m >> 16] << 16 | 0xffff
254 : scm_masktab[m >> 24] << 24 | 0xffffff)));
255 while ((r = state->rng->random_bits (state) & mask) >= m);
256 return r;
257 }
258
259 /*
260 SCM scm_c_random_bignum (scm_t_rstate *state, SCM m)
261
262 Takes a random state (source of random bits) and a bignum m.
263 Returns a bignum b, 0 <= b < m.
264
265 It does this by allocating a bignum b with as many base 65536 digits
266 as m, filling b with random bits (in 32 bit chunks) up to the most
267 significant 1 in m, and, finally checking if the resultant b is too
268 large (>= m). If too large, we simply repeat the process again. (It
269 is important to throw away all generated random bits if b >= m,
270 otherwise we'll end up with a distorted distribution.)
271
272 */
273
274 SCM
275 scm_c_random_bignum (scm_t_rstate *state, SCM m)
276 {
277 SCM result = scm_i_mkbig ();
278 const size_t m_bits = mpz_sizeinbase (SCM_I_BIG_MPZ (m), 2);
279 /* how many bits would only partially fill the last scm_t_uint32? */
280 const size_t end_bits = m_bits % (sizeof (scm_t_uint32) * SCM_CHAR_BIT);
281 scm_t_uint32 *random_chunks = NULL;
282 const scm_t_uint32 num_full_chunks =
283 m_bits / (sizeof (scm_t_uint32) * SCM_CHAR_BIT);
284 const scm_t_uint32 num_chunks = num_full_chunks + ((end_bits) ? 1 : 0);
285
286 /* we know the result will be this big */
287 mpz_realloc2 (SCM_I_BIG_MPZ (result), m_bits);
288
289 random_chunks =
290 (scm_t_uint32 *) scm_gc_calloc (num_chunks * sizeof (scm_t_uint32),
291 "random bignum chunks");
292
293 do
294 {
295 scm_t_uint32 *current_chunk = random_chunks + (num_chunks - 1);
296 scm_t_uint32 chunks_left = num_chunks;
297
298 mpz_set_ui (SCM_I_BIG_MPZ (result), 0);
299
300 if (end_bits)
301 {
302 /* generate a mask with ones in the end_bits position, i.e. if
303 end_bits is 3, then we'd have a mask of ...0000000111 */
304 const scm_t_uint32 rndbits = state->rng->random_bits (state);
305 int rshift = (sizeof (scm_t_uint32) * SCM_CHAR_BIT) - end_bits;
306 scm_t_uint32 mask = ((scm_t_uint32)-1) >> rshift;
307 scm_t_uint32 highest_bits = rndbits & mask;
308 *current_chunk-- = highest_bits;
309 chunks_left--;
310 }
311
312 while (chunks_left)
313 {
314 /* now fill in the remaining scm_t_uint32 sized chunks */
315 *current_chunk-- = state->rng->random_bits (state);
316 chunks_left--;
317 }
318 mpz_import (SCM_I_BIG_MPZ (result),
319 num_chunks,
320 -1,
321 sizeof (scm_t_uint32),
322 0,
323 0,
324 random_chunks);
325 /* if result >= m, regenerate it (it is important to regenerate
326 all bits in order not to get a distorted distribution) */
327 } while (mpz_cmp (SCM_I_BIG_MPZ (result), SCM_I_BIG_MPZ (m)) >= 0);
328 scm_gc_free (random_chunks,
329 num_chunks * sizeof (scm_t_uint32),
330 "random bignum chunks");
331 return scm_i_normbig (result);
332 }
333
334 /*
335 * Scheme level representation of random states.
336 */
337
338 scm_t_bits scm_tc16_rstate;
339
340 static SCM
341 make_rstate (scm_t_rstate *state)
342 {
343 SCM_RETURN_NEWSMOB (scm_tc16_rstate, state);
344 }
345
346
347 /*
348 * Scheme level interface.
349 */
350
351 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")));
352
353 SCM_DEFINE (scm_random, "random", 1, 1, 0,
354 (SCM n, SCM state),
355 "Return a number in [0, N).\n"
356 "\n"
357 "Accepts a positive integer or real n and returns a\n"
358 "number of the same type between zero (inclusive) and\n"
359 "N (exclusive). The values returned have a uniform\n"
360 "distribution.\n"
361 "\n"
362 "The optional argument @var{state} must be of the type produced\n"
363 "by @code{seed->random-state}. It defaults to the value of the\n"
364 "variable @var{*random-state*}. This object is used to maintain\n"
365 "the state of the pseudo-random-number generator and is altered\n"
366 "as a side effect of the random operation.")
367 #define FUNC_NAME s_scm_random
368 {
369 if (SCM_UNBNDP (state))
370 state = SCM_VARIABLE_REF (scm_var_random_state);
371 SCM_VALIDATE_RSTATE (2, state);
372 if (SCM_I_INUMP (n))
373 {
374 unsigned long m = (unsigned long) SCM_I_INUM (n);
375 SCM_ASSERT_RANGE (1, n, SCM_I_INUM (n) > 0);
376 #if SCM_SIZEOF_UNSIGNED_LONG <= 4
377 return scm_from_uint32 (scm_c_random (SCM_RSTATE (state),
378 (scm_t_uint32) m));
379 #elif SCM_SIZEOF_UNSIGNED_LONG <= 8
380 if (m <= SCM_T_UINT32_MAX)
381 return scm_from_uint32 (scm_c_random (SCM_RSTATE (state),
382 (scm_t_uint32) m));
383 else
384 {
385 scm_t_uint64 upper, lower;
386
387 upper = scm_c_random (SCM_RSTATE (state), (scm_t_uint32) (m >> 32));
388 lower = scm_c_random (SCM_RSTATE (state), SCM_T_UINT32_MAX);
389 return scm_from_uint64 ((upper << 32) | lower);
390 }
391 #else
392 #error "Cannot deal with this platform's unsigned long size"
393 #endif
394 }
395 SCM_VALIDATE_NIM (1, n);
396 if (SCM_REALP (n))
397 return scm_from_double (SCM_REAL_VALUE (n)
398 * scm_c_uniform01 (SCM_RSTATE (state)));
399
400 if (!SCM_BIGP (n))
401 SCM_WRONG_TYPE_ARG (1, n);
402 return scm_c_random_bignum (SCM_RSTATE (state), n);
403 }
404 #undef FUNC_NAME
405
406 SCM_DEFINE (scm_copy_random_state, "copy-random-state", 0, 1, 0,
407 (SCM state),
408 "Return a copy of the random state @var{state}.")
409 #define FUNC_NAME s_scm_copy_random_state
410 {
411 if (SCM_UNBNDP (state))
412 state = SCM_VARIABLE_REF (scm_var_random_state);
413 SCM_VALIDATE_RSTATE (1, state);
414 return make_rstate (SCM_RSTATE (state)->rng->copy_rstate (SCM_RSTATE (state)));
415 }
416 #undef FUNC_NAME
417
418 SCM_DEFINE (scm_seed_to_random_state, "seed->random-state", 1, 0, 0,
419 (SCM seed),
420 "Return a new random state using @var{seed}.")
421 #define FUNC_NAME s_scm_seed_to_random_state
422 {
423 SCM res;
424 if (SCM_NUMBERP (seed))
425 seed = scm_number_to_string (seed, SCM_UNDEFINED);
426 SCM_VALIDATE_STRING (1, seed);
427 res = make_rstate (scm_c_make_rstate (scm_i_string_chars (seed),
428 scm_i_string_length (seed)));
429 scm_remember_upto_here_1 (seed);
430 return res;
431
432 }
433 #undef FUNC_NAME
434
435 SCM_DEFINE (scm_datum_to_random_state, "datum->random-state", 1, 0, 0,
436 (SCM datum),
437 "Return a new random state using @var{datum}, which should have\n"
438 "been obtailed from @code{random-state->datum}.")
439 #define FUNC_NAME s_scm_datum_to_random_state
440 {
441 return make_rstate (scm_c_rstate_from_datum (datum));
442 }
443 #undef FUNC_NAME
444
445 SCM_DEFINE (scm_random_state_to_datum, "random-state->datum", 1, 0, 0,
446 (SCM state),
447 "Return a datum representation of @var{state} that may be\n"
448 "written out and read back with the Scheme reader.")
449 #define FUNC_NAME s_scm_random_state_to_datum
450 {
451 SCM_VALIDATE_RSTATE (1, state);
452 return SCM_RSTATE (state)->rng->to_datum (SCM_RSTATE (state));
453 }
454 #undef FUNC_NAME
455
456 SCM_DEFINE (scm_random_uniform, "random:uniform", 0, 1, 0,
457 (SCM state),
458 "Return a uniformly distributed inexact real random number in\n"
459 "[0,1).")
460 #define FUNC_NAME s_scm_random_uniform
461 {
462 if (SCM_UNBNDP (state))
463 state = SCM_VARIABLE_REF (scm_var_random_state);
464 SCM_VALIDATE_RSTATE (1, state);
465 return scm_from_double (scm_c_uniform01 (SCM_RSTATE (state)));
466 }
467 #undef FUNC_NAME
468
469 SCM_DEFINE (scm_random_normal, "random:normal", 0, 1, 0,
470 (SCM state),
471 "Return an inexact real in a normal distribution. The\n"
472 "distribution used has mean 0 and standard deviation 1. For a\n"
473 "normal distribution with mean m and standard deviation d use\n"
474 "@code{(+ m (* d (random:normal)))}.")
475 #define FUNC_NAME s_scm_random_normal
476 {
477 if (SCM_UNBNDP (state))
478 state = SCM_VARIABLE_REF (scm_var_random_state);
479 SCM_VALIDATE_RSTATE (1, state);
480 return scm_from_double (scm_c_normal01 (SCM_RSTATE (state)));
481 }
482 #undef FUNC_NAME
483
484 static void
485 vector_scale_x (SCM v, double c)
486 {
487 size_t n;
488 if (scm_is_simple_vector (v))
489 {
490 n = SCM_SIMPLE_VECTOR_LENGTH (v);
491 while (n-- > 0)
492 SCM_REAL_VALUE (SCM_SIMPLE_VECTOR_REF (v, n)) *= c;
493 }
494 else
495 {
496 /* must be a f64vector. */
497 scm_t_array_handle handle;
498 size_t i, len;
499 ssize_t inc;
500 double *elts;
501
502 elts = scm_f64vector_writable_elements (v, &handle, &len, &inc);
503
504 for (i = 0; i < len; i++, elts += inc)
505 *elts *= c;
506
507 scm_array_handle_release (&handle);
508 }
509 }
510
511 static double
512 vector_sum_squares (SCM v)
513 {
514 double x, sum = 0.0;
515 size_t n;
516 if (scm_is_simple_vector (v))
517 {
518 n = SCM_SIMPLE_VECTOR_LENGTH (v);
519 while (n-- > 0)
520 {
521 x = SCM_REAL_VALUE (SCM_SIMPLE_VECTOR_REF (v, n));
522 sum += x * x;
523 }
524 }
525 else
526 {
527 /* must be a f64vector. */
528 scm_t_array_handle handle;
529 size_t i, len;
530 ssize_t inc;
531 const double *elts;
532
533 elts = scm_f64vector_elements (v, &handle, &len, &inc);
534
535 for (i = 0; i < len; i++, elts += inc)
536 {
537 x = *elts;
538 sum += x * x;
539 }
540
541 scm_array_handle_release (&handle);
542 }
543 return sum;
544 }
545
546 /* For the uniform distribution on the solid sphere, note that in
547 * this distribution the length r of the vector has cumulative
548 * distribution r^n; i.e., u=r^n is uniform [0,1], so r can be
549 * generated as r=u^(1/n).
550 */
551 SCM_DEFINE (scm_random_solid_sphere_x, "random:solid-sphere!", 1, 1, 0,
552 (SCM v, SCM state),
553 "Fills @var{vect} with inexact real random numbers the sum of\n"
554 "whose squares is less than 1.0. Thinking of @var{vect} as\n"
555 "coordinates in space of dimension @var{n} @math{=}\n"
556 "@code{(vector-length @var{vect})}, the coordinates are\n"
557 "uniformly distributed within the unit @var{n}-sphere.")
558 #define FUNC_NAME s_scm_random_solid_sphere_x
559 {
560 if (SCM_UNBNDP (state))
561 state = SCM_VARIABLE_REF (scm_var_random_state);
562 SCM_VALIDATE_RSTATE (2, state);
563 scm_random_normal_vector_x (v, state);
564 vector_scale_x (v,
565 pow (scm_c_uniform01 (SCM_RSTATE (state)),
566 1.0 / scm_c_generalized_vector_length (v))
567 / sqrt (vector_sum_squares (v)));
568 return SCM_UNSPECIFIED;
569 }
570 #undef FUNC_NAME
571
572 SCM_DEFINE (scm_random_hollow_sphere_x, "random:hollow-sphere!", 1, 1, 0,
573 (SCM v, SCM state),
574 "Fills vect with inexact real random numbers\n"
575 "the sum of whose squares is equal to 1.0.\n"
576 "Thinking of vect as coordinates in space of\n"
577 "dimension n = (vector-length vect), the coordinates\n"
578 "are uniformly distributed over the surface of the\n"
579 "unit n-sphere.")
580 #define FUNC_NAME s_scm_random_hollow_sphere_x
581 {
582 if (SCM_UNBNDP (state))
583 state = SCM_VARIABLE_REF (scm_var_random_state);
584 SCM_VALIDATE_RSTATE (2, state);
585 scm_random_normal_vector_x (v, state);
586 vector_scale_x (v, 1 / sqrt (vector_sum_squares (v)));
587 return SCM_UNSPECIFIED;
588 }
589 #undef FUNC_NAME
590
591
592 SCM_DEFINE (scm_random_normal_vector_x, "random:normal-vector!", 1, 1, 0,
593 (SCM v, SCM state),
594 "Fills vect with inexact real random numbers that are\n"
595 "independent and standard normally distributed\n"
596 "(i.e., with mean 0 and variance 1).")
597 #define FUNC_NAME s_scm_random_normal_vector_x
598 {
599 long i;
600 scm_t_array_handle handle;
601 scm_t_array_dim *dim;
602
603 if (SCM_UNBNDP (state))
604 state = SCM_VARIABLE_REF (scm_var_random_state);
605 SCM_VALIDATE_RSTATE (2, state);
606
607 scm_generalized_vector_get_handle (v, &handle);
608 dim = scm_array_handle_dims (&handle);
609
610 if (scm_is_vector (v))
611 {
612 SCM *elts = scm_array_handle_writable_elements (&handle);
613 for (i = dim->lbnd; i <= dim->ubnd; i++, elts += dim->inc)
614 *elts = scm_from_double (scm_c_normal01 (SCM_RSTATE (state)));
615 }
616 else
617 {
618 /* must be a f64vector. */
619 double *elts = scm_array_handle_f64_writable_elements (&handle);
620 for (i = dim->lbnd; i <= dim->ubnd; i++, elts += dim->inc)
621 *elts = scm_c_normal01 (SCM_RSTATE (state));
622 }
623
624 scm_array_handle_release (&handle);
625
626 return SCM_UNSPECIFIED;
627 }
628 #undef FUNC_NAME
629
630 SCM_DEFINE (scm_random_exp, "random:exp", 0, 1, 0,
631 (SCM state),
632 "Return an inexact real in an exponential distribution with mean\n"
633 "1. For an exponential distribution with mean u use (* u\n"
634 "(random:exp)).")
635 #define FUNC_NAME s_scm_random_exp
636 {
637 if (SCM_UNBNDP (state))
638 state = SCM_VARIABLE_REF (scm_var_random_state);
639 SCM_VALIDATE_RSTATE (1, state);
640 return scm_from_double (scm_c_exp1 (SCM_RSTATE (state)));
641 }
642 #undef FUNC_NAME
643
644 void
645 scm_init_random ()
646 {
647 int i, m;
648 /* plug in default RNG */
649 scm_t_rng rng =
650 {
651 sizeof (scm_t_i_rstate),
652 scm_i_uniform32,
653 scm_i_init_rstate,
654 scm_i_copy_rstate,
655 scm_i_rstate_from_datum,
656 scm_i_rstate_to_datum
657 };
658 scm_the_rng = rng;
659
660 scm_tc16_rstate = scm_make_smob_type ("random-state", 0);
661
662 for (m = 1; m <= 0x100; m <<= 1)
663 for (i = m >> 1; i < m; ++i)
664 scm_masktab[i] = m - 1;
665
666 #include "libguile/random.x"
667
668 scm_add_feature ("random");
669 }
670
671 /*
672 Local Variables:
673 c-file-style: "gnu"
674 End:
675 */