【问题标题】:Using custom random number generators with Ruby Array#shuffle/sample将自定义随机数生成器与 Ruby Array#shuffle/sample 一起使用
【发布时间】:2013-05-30 05:09:20
【问题描述】:

当使用 Array#shuffle 时,Ruby 允许使用自定义随机化器,甚至提供类 Random 来使用它。以下示例使用种子值为 48 的类。

array = [1,2,3,4,5,6,7,8,9,10]
array.shuffle(random: Random.new(48))  # => [8,6,3,7,10,9,5,2,4,1] 

我写了一个小单位测试,看看有多少次一个值首先出现在打乱的数组中。

deck = (1..10).to_a
counts = Hash.new(0)

rng = Random.new

50000.times do
  counts[deck.shuffle(random: rng).first] += 1
end

1.upto(10) do |card|
  puts "#{card}:\t#{counts[card]}"
end

输出类似于以下内容:

1:  4942
2:  5100
3:  4938
4:  4960
5:  5024
6:  4992
7:  5184
8:  4930
9:  4916
10: 5014

假设我想用一个新类替换伪随机数生成器。由于 Array#shuffle 在上面的示例中似乎使用了 Random#rand,因此实现一个新类作为随机播放的 RNG 似乎很简单。在这里,我实现了一个新的伪随机数生成器,它实际上只是 rand 的一个非常简单的包装器:

deck = (1..10).to_a
counts = Hash.new(0)

class FooRandom
  def rand(max=nil)
    max.nil? ? Kernel::rand : Kernel::rand(max)
  end
end

rng = FooRandom.new

50000.times do
  counts[deck.shuffle(random: rng).first] += 1
end

1.upto(10) do |card|
  puts "#{card}:\t#{counts[card]}"
end

但是,这并没有按预期运行。 FooRandom#rand 被调用,但改组产生以下分布:

1:  0
2:  5423
3:  5562
4:  5544
5:  5512
6:  5569
7:  5535
8:  5595
9:  5524
10: 5736

如你所见,数组洗牌后数组值 1 永远不会出现在数组的第一个位置。有人知道为什么吗?

【问题讨论】:

  • 在 ruby​​-1.9.3-p392 中,我得到了两个示例的预期分布。但是在 Ruby-2.0.0-p0 中,我看到的结果和你一样。
  • 谢谢你,肖恩。是的,我正在使用 ruby​​-2.0.0-p0。

标签: ruby


【解决方案1】:

有一个 bug in Ruby 2.0.0p0 限制为 1。

这已在 Ruby 2.0.0p195 中修复,因此您应该升级您的安装。

【讨论】:

  • 感谢发布(并报告错误)。我怀疑这可能是一个错误,并打算在今天进行调查。
【解决方案2】:

在 ruby​​ 1.9.3 中,最大值为零。在 Ruby 2.0.0 中,max 被传递给 rand。我可以通过将 rand 方法更改为以下方法来使其工作。

class FooRandom
  def rand(max=nil)
    max.nil? ? Kernel::rand : Kernel::rand(max+1)
  end
end

以前是差一档的。

这是 C 源代码的摘录 http://ruby-doc.org/core-2.0/Array.html#method-i-shuffle

i = RARRAY_LEN(ary);
ptr = RARRAY_PTR(ary);
while (i) {
    long j = RAND_UPTO(i);
    VALUE tmp;
    tmp = ptr[--i];
    ptr[i] = ptr[j];
    ptr[j] = tmp;
}
return ary;

}

【讨论】:

  • 肖恩,效果很好!我想知道是否从 1.9.3 对 rand 进行了更改。到 2.0.0 是故意的还是一个错误?
  • @ThaiDoan:这是一个错误,请参阅我的回答。
猜你喜欢
  • 1970-01-01
  • 2014-01-23
  • 2021-05-24
  • 2011-09-17
  • 1970-01-01
  • 1970-01-01
  • 2023-01-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多