diff --git a/sys/include/random.h b/sys/include/random.h index 48b978782fedf1d5dd97b31b1f2e2ef90b71c175..252a8379cfb9af117cf688af11880389673a6b8c 100644 --- a/sys/include/random.h +++ b/sys/include/random.h @@ -92,10 +92,7 @@ void random_bytes(uint8_t *buf, size_t size); * * @return a random number on [a,b)-interval */ -static inline uint32_t random_uint32_range(uint32_t a, uint32_t b) -{ - return (random_uint32() % (b - a)) + a; -} +uint32_t random_uint32_range(uint32_t a, uint32_t b); #if PRNG_FLOAT /* These real versions are due to Isaku Wada, 2002/01/09 added */ diff --git a/sys/random/random.c b/sys/random/random.c index dc5e6cf38dfb889d7c22a534a4808be9ea46cbff..ad80880167f90dfeaf262a8791ff6631c159fb6c 100644 --- a/sys/random/random.c +++ b/sys/random/random.c @@ -54,3 +54,30 @@ void random_bytes(uint8_t *target, size_t n) *target++ = *random_pos++; } } + +uint32_t random_uint32_range(uint32_t a, uint32_t b) +{ + assert(a < b); + + uint32_t divisor, rand_val, range = b - a; + uint8_t range_msb = bitarithm_msb(range); + + /* check if range is a power of two */ + if (!(range & (range - 1))) { + divisor = (1 << range_msb) - 1; + } + else if (range_msb < 31) { + /* leftshift for next power of two interval */ + divisor = (1 << (range_msb + 1)) -1; + } + else { + /* disable modulo operation in loop below */ + divisor = UINT32_MAX; + } + /* get random numbers until value is smaller than range */ + do { + rand_val = (random_uint32() & divisor); + } while (rand_val >= range); + /* return random in range [a,b] */ + return (rand_val + a); +}