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