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