递归和内核的奇怪行为#rand(Ruby)

时间:2015-04-17 05:28:33

标签: ruby recursion random

我在Ruby中有这样的方法:

def guess
  random_guess = rand(4)
  if random_guess == 0
    guess
  end

  puts random_guess
end
guess

正如你所看到的,它意味着生成一个介于0和4之间的随机数,然后在数字为0时重复出现。这个想法是让方法永远不会打印出来。但是,它似乎不是出于某种奇怪的原因这样做。例如,以下是random_guess获取值0时IRB中的示例:

2.2.0 :001 > def guess
2.2.0 :002?>     random_guess = rand(4)
2.2.0 :003?>     if random_guess == 0
2.2.0 :004?>         guess
2.2.0 :005?>       end
2.2.0 :006?>     
2.2.0 :007 >       puts random_guess
2.2.0 :008?>   end
 => :guess 
2.2.0 :009 > guess
2
0
0
0
0
 => nil 
2.2.0 :010 > 

当它没有得到值0时,程序运行正常,只是打印出该范围内的任何其他随机数:

2.2.0 :010 > guess
1
 => nil 
2.2.0 :011 > 

我想知道的是,为什么程序在random_guess为0时发生的递归行为如此奇怪。看起来它是反复发生的,但似乎并没有在正确的条件下停止,即当random_guess不为0时。为什么会发生这种情况?

5 个答案:

答案 0 :(得分:2)

random_guess0时,guess会递归调用自身,这是正常的。您看到的输出是因为{/ 1}}在递归后执行。所以当你看到输出时,例如:

puts random_guess
  1. 3 0 被称为:guess获取random_guess,因此请致电0
  2. 内部 guess内,guess获取random_guess, 当前3,即random_guess。退出内部 3
  3. guess的值放在 outter random_guess中,这是 guess,然后退出。

答案 1 :(得分:0)

这正是你告诉它的。如果得到非零值,则不输入if - 子句,因此立即打印非零并完成。

但是,如果生成的第一个值为零,则输入递归并重复该过程,直到产生非零值。只有这样你才能绕过if来遇到print语句并从递归中返回。由于只有在零时才调用递归,现在打印该零并返回。

净结果,输出将是一个非零值,然后是所有出现的零,当你弹出堆栈时,它们的顺序相反。

答案 2 :(得分:0)

因为recursive。保持每个剩余指令的堆栈。

如果0出现,它将在堆栈中添加puts random_guess行。在完成递归guess调用后,它会弹出剩余的指令。

所以它打印0直到guess的许多递归调用。

答案 3 :(得分:0)

# closer to your original design
# fyi, returns values 1 - 3
def guess
  random_guess = 0
  while random_guess == 0
    random_guess = get_random_guess(4)
  end

  random_guess
end

def get_random_guess(max_guess)
    rand(4)
end

# test guess 100 times
(1..100).each { puts "guess=#{guess}" }



# faster, note the use of rand without a max parameter. 
# in this case, rand returns a float between 0 and 1
# this return values between min_guess and max_guess
def faster_guess(min_guess, max_guess)
  (rand() * (max_guess + 1 - min_guess)).to_i + min_guess
end

# test faster_guess 100 times
# will return values between 1 - 4
(1..100).each { puts "faster_guess=#{faster_guess(1,4)}" }

答案 4 :(得分:0)

因为您将puts语句放在方法中,所以它会在每次调用时打印出随机猜测的值,无论是0还是0。递归调用自身的方法只会暂时中断该点的控制流,直到它向上移回堆栈。

您要做的是让方法返回不是def guess random_guess = rand(4) (random_guess > 0) ? random_guess : guess end puts guess # 1 (never 0) 的第一个值。例如:

random_guess

在此修改方法中,如果条件大于0,则条件将返回{{1}}。如果没有,它将递归调用自身,直到满足条件。

请注意,这种递归理论上的使用创建了无限递归的可能性,虽然这在实践中永远不会发生,但该方法的执行时间将是随机的。