summaryrefslogtreecommitdiff
path: root/random.c
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-05-10 06:46:09 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-05-10 06:46:09 +0000
commit15fbd05e4e53798ee80cc21af22a53edc3c8229b (patch)
tree6dd83cc1b20eff5054137ccc305f85bd14ca8b46 /random.c
parentb402cc71616169bab03fb856e73a7d6519330ca3 (diff)
downloadruby-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.c16
1 files changed, 14 insertions, 2 deletions
diff --git a/random.c b/random.c
index 21d1ea0840..a3476d5203 100644
--- a/random.c
+++ b/random.c
@@ -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;