为什么这两个输入产生不同的输出?

时间:2017-04-04 23:24:10

标签: ruby debugging recursion

所以我有以下Ruby脚本:

def f( a , b , c )
  if b < 0
    p = q = 1
    if c[ 0 ] < 0
      while p != 0
        if p == c.length
          p = 0
          return a + 1
        elsif c[ p ] < 0
          p += 1
        else
          c[ p ] -= 1
          c[ p - 1 ] = a
          p = 0
          return f( a , b , c )
        end
      end
    else
      c[ 0 ] -= 1
      return f( a , a , c )
    end
  else
    return f( f( a , -1 , c ) , b-1 , c )
  end
end

#Why do the below two return different numbers?
f( 2 , 0 , [ 0 , -1 ] )
f( f( 2 , -1 , [ 0 , -1 ] ) , -1 , [ 0 , -1 ] )

他们应该回归同样的事情。由于第一个参数的第二个参数大于或等于零,我们应该让它运行到最后else的情况并返回f(f(2,-1,[0,1]),-1,[0,1]),但是当我运行这两个时,它们不会返回相同的结果

https://repl.it/GvD3/10

根据以上链接,我们有

f(2,0,[0,-1]) = 7
f(f(2,-1,[0,-1]),-1,[0,-1]) = 14

我无法弄清楚我在这里做错了什么。 (如果你能解决这个问题,也要感谢)

对于长度为4的数组c,该函数应如下所示:

https://repl.it/GvD3/17

一些示例说明了这应该如何工作:

  f(3,1,[2,3])
= f(f(3,-1,[2,3]),0,[2,3])
= f(f(3,3,[1,3]),0,[2,3])
= f(f(f(3,-1,[1,3]),2,[1,3]),0,[2,3])
= f(f(f(3,3,[0,3]),2,[1,3]),0,[2,3])
= f(f(f(f(3,-1,[0,3]),2,[0,3]),2,[1,3]),0,[2,3])
= f(f(f(f(3,3,[-1,3]),2,[0,3]),2,[1,3]),0,[2,3])
= f(f(f(f(f(3,-1,[-1,3]),2,[-1,3]),2,[0,3]),2,[1,3]),0,[2,3])
= f(f(f(f(f(3,-1,[3,2]),2,[-1,3]),2,[0,3]),2,[1,3]),0,[2,3])
= f(f(f(f(f(3,3,[2,2]),2,[-1,3]),2,[0,3]),2,[1,3]),0,[2,3])

现在我要诚实地告诉你,f(3,1,[2,3])比你通常处理的任何事情要大得多。事实上,我正在制作的节目几乎总会返回stack level too deep,因为我正在经历的筹码数量绝对是精神错乱。我应该在具有无限资源等的理论计算机上运行它,并且我正在尝试重新创建一个没有@符号的FAIL版本。

对此的一般解释:

如果是b>-1,那么我们在第一个参数中进行b+1函数的嵌套:

f(a,3,c) = f(f(f(f(a,-1,c),-1,c),-1,c),-1,c)

如果b=-1c0=-1的第一个元素,则用第一个参数替换第二个参数。

f(a,-1,[c0, c1, ...]) = f(a,a,[c0 - 1, c1, ...])

否则,如果第二个元素是-1,则用第一个参数替换第一个元素,否则,如果第三个元素是-1,则用第一个参数替换第二个元素等。

如果第二个参数和数组的所有元素都是-1,那么我们有

f(a,-1,c) = a + 1

更直观地说,我们有:(不是真正的平等)

f(a,-1,[-1,-1,-1, ...]) = addition
f(a,-1,[ 0,-1,-1, ...]) = repeated addition = multiplication
f(a,-1,[ 1,-1,-1, ...]) = repeated multiplication = exponentiation
f(a,-1,[ 2,-1,-1, ...]) = repeated exponentiation = tetration
...
f(a,-1,[-1, 0,-1, ...]) = Ackermann function (it climbs up the previous functions)
f(a,-1,[ 0, 0,-1, ...]) = repeated Ackermann functions
f(a,-1,[ 1, 0,-1, ...]) = repeated previous function nested into itself
f(a,-1,[ 2, 0,-1, ...]) = repeated previous function nested into itself
...
f(a,-1,[-1, 1,-1, ...]) = some function that climbs up through the list of previous functions
...
f(a,-1,[-1,-1, 0, ...]) = some function that climbs through functions of the form f(a,-1,[-1, k,-1, ...])
f(a,-1,[ 0,-1, 0, ...]) = repeated nesting of the previous function
f(a,-1,[-1, 0, 0, ...]) = some function that climbs through function of the form f(a,-1,[ k,-1, 0, ...])
f(a,-1,[ 0,-1, 1, ...]) = some function that climbs through functions of the form f(a,-1,[ 0, k, 0, ...])

我希望你能得到一般的想法。

Ackermann function

1 个答案:

答案 0 :(得分:2)

这是因为你在函数调用中修改了数组c 的元素。当函数返回时, c 是修改过的,而不是原始的。新的 c 会在后续的函数调用中使用,从而导致您获得的行为。

修改

以下是对 f(2,0,[0,-1]) 评估方式的解释:

  • 函数调用不满足条件 b < 0 ,因此它将转到上一个else语句并执行f( f(a ,-1 ,c), b-1, c)

  • 内部通话为f(a,-1,c),即f(2, -1, [0,-1])。这将返回值 6 。此外,在此评估期间,它会将 c 修改为[-1,-1]

  • 外部通话现在为f(6,b-1,c),即f(6, -1, [-1,-1] )。请注意,c 不再 [0,-1]了。这将评估为 7

因此,等效调用应为: f(f(2,-1,[0,-1]),-1,[-1,-1]) ,这将产生相同的结果 7