diff --git a/libguile/random.c b/libguile/random.c index 83870f6ad..c0a3e046b 100644 --- a/libguile/random.c +++ b/libguile/random.c @@ -241,21 +241,42 @@ scm_c_exp1 (scm_t_rstate *state) unsigned char scm_masktab[256]; -scm_t_uint32 -scm_c_random (scm_t_rstate *state, scm_t_uint32 m) +static inline scm_t_uint32 +scm_i_mask32 (scm_t_uint32 m) { - scm_t_uint32 r, mask; - mask = (m < 0x100 + return (m < 0x100 ? scm_masktab[m] : (m < 0x10000 ? scm_masktab[m >> 8] << 8 | 0xff : (m < 0x1000000 ? scm_masktab[m >> 16] << 16 | 0xffff : scm_masktab[m >> 24] << 24 | 0xffffff))); +} + +scm_t_uint32 +scm_c_random (scm_t_rstate *state, scm_t_uint32 m) +{ + scm_t_uint32 r, mask = scm_i_mask32 (m); while ((r = state->rng->random_bits (state) & mask) >= m); return r; } +scm_t_uint64 +scm_c_random64 (scm_t_rstate *state, scm_t_uint64 m) +{ + scm_t_uint64 r; + scm_t_uint32 mask; + + if (m <= SCM_T_UINT32_MAX) + return scm_c_random (state, (scm_t_uint32) m); + + mask = scm_i_mask32 (m >> 32); + while ((r = ((scm_t_uint64) (state->rng->random_bits (state) & mask) << 32) + | state->rng->random_bits (state)) >= m) + ; + return r; +} + /* SCM scm_c_random_bignum (scm_t_rstate *state, SCM m) @@ -377,17 +398,8 @@ SCM_DEFINE (scm_random, "random", 1, 1, 0, return scm_from_uint32 (scm_c_random (SCM_RSTATE (state), (scm_t_uint32) m)); #elif SCM_SIZEOF_UNSIGNED_LONG <= 8 - if (m <= SCM_T_UINT32_MAX) - return scm_from_uint32 (scm_c_random (SCM_RSTATE (state), - (scm_t_uint32) m)); - else - { - scm_t_uint64 upper, lower; - - upper = scm_c_random (SCM_RSTATE (state), (scm_t_uint32) (m >> 32)); - lower = scm_c_random (SCM_RSTATE (state), SCM_T_UINT32_MAX); - return scm_from_uint64 ((upper << 32) | lower); - } + return scm_from_uint64 (scm_c_random64 (SCM_RSTATE (state), + (scm_t_uint64) m)); #else #error "Cannot deal with this platform's unsigned long size" #endif diff --git a/libguile/random.h b/libguile/random.h index 512b7d259..2f1f0f69a 100644 --- a/libguile/random.h +++ b/libguile/random.h @@ -67,6 +67,7 @@ SCM_API double scm_c_uniform01 (scm_t_rstate *); SCM_API double scm_c_normal01 (scm_t_rstate *); SCM_API double scm_c_exp1 (scm_t_rstate *); SCM_API scm_t_uint32 scm_c_random (scm_t_rstate *, scm_t_uint32 m); +SCM_API scm_t_uint64 scm_c_random64 (scm_t_rstate *state, scm_t_uint64 m); SCM_API SCM scm_c_random_bignum (scm_t_rstate *, SCM m);