diff options
author | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2016-05-10 06:46:09 +0000 |
---|---|---|
committer | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2016-05-10 06:46:09 +0000 |
commit | 15fbd05e4e53798ee80cc21af22a53edc3c8229b (patch) | |
tree | 6dd83cc1b20eff5054137ccc305f85bd14ca8b46 /random.c | |
parent | b402cc71616169bab03fb856e73a7d6519330ca3 (diff) | |
download | ruby-15fbd05e4e53798ee80cc21af22a53edc3c8229b.tar.gz |
random.c: reuse bits
* random.c (random_ulong_limited): reduce calling bytes methods by
reusing dropped bits.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@54969 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'random.c')
-rw-r--r-- | random.c | 16 |
1 files changed, 14 insertions, 2 deletions
@@ -991,9 +991,21 @@ random_ulong_limited(VALUE obj, rb_random_t *rnd, unsigned long limit) { if (!limit) return 0; if (!rnd) { - unsigned long val, mask = make_mask(limit); + const int w = sizeof(limit) * CHAR_BIT - nlz_long(limit); + const int n = w > 32 ? sizeof(unsigned long) : sizeof(uint32_t); + const unsigned long mask = ~(~0UL << w); + const unsigned long full = ~(~0UL << n * CHAR_BIT); + unsigned long val, bits = 0, rest = 0; do { - obj_random_bytes(obj, &val, sizeof(unsigned long)); + if (mask & ~rest) { + union {uint32_t u32; unsigned long ul;} buf; + obj_random_bytes(obj, &buf, n); + rest = full; + bits = (n == sizeof(uint32_t)) ? buf.u32 : buf.ul; + } + val = bits; + bits >>= w; + rest >>= w; val &= mask; } while (limit < val); return val; |