1 |
/* Copyright (C) 1999,2000,2001 Free Software Foundation, Inc. |
/* Copyright (C) 1999,2000,2001, 2003 Free Software Foundation, Inc. |
2 |
* This program is free software; you can redistribute it and/or modify |
* This program is free software; you can redistribute it and/or modify |
3 |
* it under the terms of the GNU General Public License as published by |
* it under the terms of the GNU General Public License as published by |
4 |
* the Free Software Foundation; either version 2, or (at your option) |
* the Free Software Foundation; either version 2, or (at your option) |
265 |
return r; |
return r; |
266 |
} |
} |
267 |
|
|
268 |
|
/* |
269 |
|
SCM scm_c_random_bignum (scm_t_rstate *state, SCM m) |
270 |
|
|
271 |
|
Takes a random state (source of random bits) and a bignum m. |
272 |
|
Returns a bignum b, 0 <= b < m. |
273 |
|
|
274 |
|
It does this by allocating a bignum b with as many base 65536 digits |
275 |
|
as m, filling b with random bits (in 32 bit chunks) up to the most |
276 |
|
significant 1 in m, and, finally checking if the resultant b is too |
277 |
|
large (>= m). If too large, we simply repeat the process again. (It |
278 |
|
is important to throw away all generated random bits if b >= m, |
279 |
|
otherwise we'll end up with a distorted distribution.) |
280 |
|
|
281 |
|
*/ |
282 |
|
|
283 |
SCM |
SCM |
284 |
scm_c_random_bignum (scm_t_rstate *state, SCM m) |
scm_c_random_bignum (scm_t_rstate *state, SCM m) |
285 |
{ |
{ |
287 |
int i, nd; |
int i, nd; |
288 |
LONG32 *bits, mask, w; |
LONG32 *bits, mask, w; |
289 |
nd = SCM_NUMDIGS (m); |
nd = SCM_NUMDIGS (m); |
290 |
/* calculate mask for most significant digit */ |
/* Compute a 32-bit bitmask for use when filling bits into the most |
291 |
|
significant long word in b's bit space. A combination of |
292 |
|
conditionals and an 8-bit lookup table (scm_masktab) is used. |
293 |
|
*/ |
294 |
#if SIZEOF_INT == 4 |
#if SIZEOF_INT == 4 |
295 |
/* 16 bit digits */ |
/* 16 bit digits */ |
296 |
if (nd & 1) |
if (nd & 1) |
316 |
? scm_masktab[w >> 16] << 16 | 0xffff |
? scm_masktab[w >> 16] << 16 | 0xffff |
317 |
: scm_masktab[w >> 24] << 24 | 0xffffff)); |
: scm_masktab[w >> 24] << 24 | 0xffffff)); |
318 |
} |
} |
319 |
|
/* allocate b and assign the bit space address to the variable "bits" */ |
320 |
b = scm_i_mkbig (nd, 0); |
b = scm_i_mkbig (nd, 0); |
321 |
bits = (LONG32 *) SCM_BDIGITS (b); |
bits = (LONG32 *) SCM_BDIGITS (b); |
322 |
do |
do |
323 |
{ |
{ |
324 |
i = nd; |
i = nd; |
325 |
/* treat most significant digit specially */ |
/* generate the most significant bits using the mask */ |
326 |
#if SIZEOF_INT == 4 |
#if SIZEOF_INT == 4 |
327 |
/* 16 bit digits */ |
/* 16 bit digits */ |
328 |
if (i & 1) |
if (i & 1) |
347 |
/* now fill up the rest of the bignum */ |
/* now fill up the rest of the bignum */ |
348 |
while (i) |
while (i) |
349 |
bits[--i] = scm_the_rng.random_bits (state); |
bits[--i] = scm_the_rng.random_bits (state); |
350 |
|
/* use scm_i_normbig to cut away leading zeros and/or convert to inum */ |
351 |
b = scm_i_normbig (b); |
b = scm_i_normbig (b); |
352 |
if (SCM_INUMP (b)) |
if (SCM_INUMP (b)) |
353 |
return b; |
return b; |
354 |
|
/* if b >= m, regenerate b (it is important to regenerates all |
355 |
|
bits in order not to get a distorted distribution) |
356 |
|
*/ |
357 |
} while (scm_bigcomp (b, m) <= 0); |
} while (scm_bigcomp (b, m) <= 0); |
358 |
return b; |
return b; |
359 |
} |
} |