Skip to content

Commit d6ec8c9

Browse files
committed
[GR-19220] Reverse Array#shuffle implementation to match output of CRuby (#2985)
PullRequest: truffleruby/3757
2 parents fa3246f + 7954d84 commit d6ec8c9

File tree

3 files changed

+17
-4
lines changed

3 files changed

+17
-4
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ Bug fixes:
88

99
Compatibility:
1010

11-
- Fix `Hash#shift` when Hash is empty but has initial default value or initial default proc (@itarato).
11+
* Fix `Hash#shift` when Hash is empty but has initial default value or initial default proc (@itarato).
12+
* Make `Array#shuffle` produce the same results as CRuby (@rwstauner).
1213

1314
Performance:
1415

spec/ruby/core/array/shuffle_spec.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,14 @@
9393
-> { ArraySpecs.frozen_array.shuffle! }.should raise_error(FrozenError)
9494
-> { ArraySpecs.empty_frozen_array.shuffle! }.should raise_error(FrozenError)
9595
end
96+
97+
it "matches CRuby with random:" do
98+
%w[a b c].shuffle(random: Random.new(1)).should == %w[a c b]
99+
(0..10).to_a.shuffle(random: Random.new(10)).should == [2, 6, 8, 5, 7, 10, 3, 1, 0, 4, 9]
100+
end
101+
102+
it "matches CRuby with srand" do
103+
srand(123)
104+
%w[a b c d e f g h i j k].shuffle.should == %w[a e f h i j d b g k c]
105+
end
96106
end

src/main/ruby/truffleruby/core/array.rb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,9 +1240,11 @@ def shuffle!(options = undefined)
12401240
random_generator = options[:random] if options[:random].respond_to?(:rand)
12411241
end
12421242

1243-
size.times do |i|
1244-
r = i + random_generator.rand(size - i).to_int
1245-
raise RangeError, "random number too big #{r - i}" if r < 0 || r >= size
1243+
# Start at the end and work toward the beginning for compatibility with CRuby.
1244+
(size - 1).downto(0) do |i|
1245+
r = random_generator.rand(i + 1).to_int
1246+
raise RangeError, "random number too small #{r}" if r < 0
1247+
raise RangeError, "random number too big #{r}" if r > i
12461248
swap(i, r)
12471249
end
12481250
self

0 commit comments

Comments
 (0)