diff --git a/lib/srfi/27/rand.c b/lib/srfi/27/rand.c index 13d4cc4d..678ecbfc 100644 --- a/lib/srfi/27/rand.c +++ b/lib/srfi/27/rand.c @@ -49,8 +49,9 @@ static sexp sexp_rs_random_integer (sexp ctx, sexp self, sexp_sint_t n, sexp rs, sexp res; sexp_int32_t m; #if SEXP_USE_BIGNUMS - sexp_uint32_t mod; - sexp_int32_t hi, len, i, *data; + sexp_uint_t mod; + sexp_uint32_t *data; + sexp_int32_t hi, len, i; #endif if (! sexp_random_source_p(rs)) res = sexp_type_exception(ctx, self, rs_type_id, rs); @@ -62,21 +63,35 @@ static sexp sexp_rs_random_integer (sexp ctx, sexp self, sexp_sint_t n, sexp rs, hi = sexp_bignum_hi(bound); len = hi * (sizeof(sexp_uint_t) / sizeof(sexp_int32_t)); res = sexp_make_bignum(ctx, hi + 1); - data = (sexp_int32_t*) sexp_bignum_data(res); - for (i=0; i bound to < bound, and stop as */ /* soon as we are sure the result is within bound. */ - for (i = hi-1; i >= 0; i--) { + for (i = hi-1; i >= 0; --i) { mod = sexp_bignum_data(bound)[i]; - if (mod && sexp_bignum_data(res)[i] > mod) { - sexp_bignum_data(res)[i] %= mod; + if (mod) { + if (i > 0 && mod < SEXP_UINT_T_MAX) { + /* allow non-final bigits to be == */ + ++mod; + } + if (sexp_bignum_data(res)[i] >= mod) + sexp_bignum_data(res)[i] %= mod; + } else { + sexp_bignum_data(res)[i] = 0; } - if (sexp_bignum_data(res)[i] != mod) { + if (sexp_bignum_data(res)[i] < sexp_bignum_data(bound)[i]) { break; } + if (i == 0) { + /* handle the case where all bigits are == */ + if (sexp_bignum_data(res)[i] > 0) + --sexp_bignum_data(res)[i]; + else + res = sexp_sub(ctx, res, SEXP_ONE); + } } #endif } else {