从初始化程序调用时,Ruby随机数生成器会出现偏差

Jac*_*eve 3 ruby

我正在尝试模拟Monty Hall问题,其中要求用户选择三个门中的一个,然后提供切换门.我正在寻找一个随机变化的选择,应该在50%的转换范围内,而50%的停留时间.

class Scenario
  def initialize
    # switched?
  end

  def switched?
    @sw ||= [true, false].sample
  end
end

results = { switched: [], stayed: [] }

1000.times do
  s = Scenario.new

  if s.switched?
    results[:switched].push(s)
  else
    results[:stayed].push(s)
  end
end

puts results[:switched].count
puts results[:stayed].count
Run Code Online (Sandbox Code Playgroud)

当我检查结果哈希时,在此示例中,数组计数按预期大约为500/500.

但是,如果我switched?在初始化方法中取消注释,结果往往会被拆分为750/250左右.结果仍然是随机的(例如738到262),但它们总是倾向于成为这个问题的错误解决方案.

我也尝试过使用其他机制rand(2).zero?来生成数据,但是会出现同样的问题.

为什么或如何在初始化程序中调用此memoized函数会导致随机变化到目前为止,但始终关闭?

Tom*_*ord 5

在红宝石中,除了nil和之外的所有值false都被认为是"真实的".

当你打电话时foo ||= bar,bar将评估当且是否foo只是"假" - 即等于nil false.(或者如果它未定义!)

在您的代码中,您有以下内容:

def switched?
  @sw ||= [true, false].sample
end
Run Code Online (Sandbox Code Playgroud)

因此,只有返回 !! @sw变量才会记住方法调用的结果![true, false].sampletrue

那么,这意味着如果你switched?多次打电话,你就会给@sw变量"多次尝试"随机选择true.

如果你打电话switched?一次,它有50%的可能性true.叫它两次,有75%的几率(正如你所观察到的).称它为3次,有87.5%的几率.等等.

为了记住潜在的false价值,您需要对语法更加明确 - 例如

def switched?
  return @sw if defined?(@sw)
  @sw = [true, false].sample 
end
Run Code Online (Sandbox Code Playgroud)

您现在可以switched?安全地多次呼叫.它会记住它的第一个结果,即使是false,而不是重新计算它.