rubyspec/rubyspec — pull request #179 by jamesotron (2013-02-24 23:46:06+00:00)
Title: Array#shuffle and #sample only use Kernel#rand on Rubnius

On Rubinius Array#shuffle and Array#sample use Kernel#rand as their
source of randomness, however on both MRI and JRuby randomness is
achieved using implementation specific methods.

- MRI:

```c
#define RAND_UPTO(max) (long)rb_random_ulong_limited((randgen), (max)-1)

static VALUE
rb_ary_shuffle_bang(int argc, VALUE *argv, VALUE ary)
{
VALUE *ptr, opts, *snap_ptr, randgen = rb_cRandom;
long i, snap_len;

if (OPTHASH_GIVEN_P(opts)) {
randgen = rb_hash_lookup2(opts, sym_random, randgen);
}
rb_check_arity(argc, 0, 0);
rb_ary_modify(ary);
i = RARRAY_LEN(ary);
ptr = RARRAY_PTR(ary);
snap_len = i;
snap_ptr = ptr;
while (i) {
long j = RAND_UPTO(i);
VALUE tmp;
if (snap_len != RARRAY_LEN(ary) || snap_ptr != RARRAY_PTR(ary)) {
rb_raise(rb_eRuntimeError, "modified during shuffle");
}
tmp = ptr[--i];
ptr[i] = ptr[j];
ptr[j] = tmp;
}
return ary;
}
```

- JRuby:

```java
@JRubyMethod(name = "shuffle!", optional = 1, compat = RUBY1_9)
public IRubyObject shuffle_bang(ThreadContext context, IRubyObject[] args) {
modify();
IRubyObject randgen = context.runtime.getRandomClass();
if (args.length > 0) {
IRubyObject hash = TypeConverter.checkHashType(context.runtime, args[args.length - 1]);
if (!hash.isNil()) {
randgen = ((RubyHash) hash).fastARef(context.runtime.newSymbol("random"));
}
}
int i = realLength;
try {
while (i > 0) {
int r = (int) (RubyRandom.randomReal(context, randgen) * i);
IRubyObject tmp = eltOk(--i);
values[begin + i] = eltOk(r);
values[begin + r] = tmp;
}
} catch (ArrayIndexOutOfBoundsException e) {
concurrentModification();
}

return this;
}
```

Therefore, I have only specified this behaviour on Rubinius.