ruby中的递归乘法器

ruby中的递归乘法器,ruby,recursion,Ruby,Recursion,我正在尝试用ruby创建一个递归乘法器 @j = 0 def multiplier(x, y, z) count = 0 if x > 0 if z > 0 @j += y z -= 1 count += 1 multiplier(x, y, z) else x -= 1 z = count

我正在尝试用ruby创建一个递归乘法器

@j = 0

def multiplier(x, y, z)
    count = 0
    if x > 0
        if z > 0
            @j += y
            z -= 1
            count += 1
            multiplier(x, y, z)
        else
            x -= 1
            z = count
            p z
            multiplier(x, y, z)
        end
    else
        return @j
    end
end


def main
    puts "Calculation is: " + multiplier(3, 10, 4).to_s
end

main
X是乘法发生的次数

Y是我们要乘的数

Z是我们乘以的数字

代码应输出带有变量的120

我很难让Z保持我所需要的状态。另外,我更喜欢在没有全局变量的情况下执行此操作


因此,类似于x*(y*z)但没有时间符号的代码的主要问题是
count
是一个局部变量,它不会在递归调用之间保存。此外,如果要避免全局变量,请在调用函数时将变量作为附加参数传递。在FP中,我们称之为累加器:


上面肯定缺少必要的输入有效性检查,但我敢打赌你一定知道了。

代码的主要问题是
count
是一个局部变量,它不会在递归调用之间保存。此外,如果要避免全局变量,请在调用函数时将变量作为附加参数传递。在FP中,我们称之为累加器:


上面肯定缺少对输入有效性的必要检查,但我敢打赌你一定明白了。

我想说ruby中惯用的方法是使用迭代器,而不是递归/循环

def multiplier(x, y, z)
  x.times.map do
    y.times.map do
      z
    end.reduce(:+)
  end.reduce(:+)
end

或者如果唯一的操作是
inc

def multiplier(x, y, z)
  j = 0
  x.times do
    y.times do
      z.times do
        j += 1
      end
    end
  end
  j
end
输出是相同的

multiplier(3, 10, 4)
# 120
对于任意数量的参数,我们必须使用递归

def multiplier(*xs, res: 0)
  return res if xs.empty?
  xs[0].times do
    res += 1 if xs.size == 1
    res = multiplier(*xs.drop(1), res: res)
  end
  res
end


我想说ruby中惯用的方法是使用迭代器,而不是递归/循环

def multiplier(x, y, z)
  x.times.map do
    y.times.map do
      z
    end.reduce(:+)
  end.reduce(:+)
end

或者如果唯一的操作是
inc

def multiplier(x, y, z)
  j = 0
  x.times do
    y.times do
      z.times do
        j += 1
      end
    end
  end
  j
end
输出是相同的

multiplier(3, 10, 4)
# 120
对于任意数量的参数,我们必须使用递归

def multiplier(*xs, res: 0)
  return res if xs.empty?
  xs[0].times do
    res += 1 if xs.size == 1
    res = multiplier(*xs.drop(1), res: res)
  end
  res
end

在此基础上,这里有一个更通用的函数,它可以获取任意长的正整数列表,并通过递归加法将其相乘:

def multiplier(*integers, accum: 0)
  if integers.size == 1
    # We are finished!
    integers[0]
  elsif integers[-1].positive?
    # "Multiply" the last two integers, by recursive addition
    integers[-1] -= 1
    multiplier(*integers, accum: accum + integers[-2])
  else
    # The above multiplication is complete; set the last integer to its result
    integers[-2] = accum
    multiplier(*integers[0..-2])
  end
end
在此基础上,这里有一个更通用的函数,它可以获取任意长的正整数列表,并通过递归加法将其相乘:

def multiplier(*integers, accum: 0)
  if integers.size == 1
    # We are finished!
    integers[0]
  elsif integers[-1].positive?
    # "Multiply" the last two integers, by recursive addition
    integers[-1] -= 1
    multiplier(*integers, accum: accum + integers[-2])
  else
    # The above multiplication is complete; set the last integer to its result
    integers[-2] = accum
    multiplier(*integers[0..-2])
  end
end

我首先写一个方法,递归地将两个数字相乘:

def multiply_2(a, b)
  return 0 if a.zero?
  b + multiply_2(a - 1, b)
end

multiply_2(3, 4)
#=> 12
在这个方法的基础上乘以三个数字:

def multiply_3(a, b, c)
  multiply_2(multiply_2(a, b), c)
end

multiply_3(3, 4, 10)
#=> 3
并最终扩展到处理n个数字:


请注意,对于较大的数字,您可能会遇到
SystemStackError
。这可以通过使
乘法\u 2
(把它作为练习,这并不难)和启用Ruby的
:tailcall\u优化

来避免。我首先写一个方法,递归地将两个数字相乘:

def multiply_2(a, b)
  return 0 if a.zero?
  b + multiply_2(a - 1, b)
end

multiply_2(3, 4)
#=> 12
在这个方法的基础上乘以三个数字:

def multiply_3(a, b, c)
  multiply_2(multiply_2(a, b), c)
end

multiply_3(3, 4, 10)
#=> 3
并最终扩展到处理n个数字:


请注意,对于较大的数字,您可能会遇到
SystemStackError
。这可以通过使
乘法\u 2
(把它作为一个练习,并不难)和启用Ruby的
:tailcall\u优化来避免,它可以这样编写

def multiplier(*args)
  prod = recurse(*args.map(&:abs))
  args.count { |n| n < 0 }.even? ? prod : -prod
end

def recurse(first, *rest)
  first.zero? || rest.empty? ? first : ([recurse(*rest)]*first).sum
end

multiplier(3,  10,  4)        #=>  120
multiplier(3,  10,  4, 2, 3)  #=>  720
multiplier(3, -10,  4)        #=> -120
multiplier(3, -10, -4)        #=>  120
multiplier(3,   0,  4)        #=>    0
multiplier(3,   0, -4)        #=>    0
所以我们计算

([recurse(4)]*3).sum
在递归(4)

由于
rest.empty#=>true
recurse
返回
first#=>4
,因此

([recurse(4)]*3).sum]
  #=> ([4]*3).sum => [4,4,4].sum => 12

返回到
乘数
。由于
[3,-4]
包含奇数个负值,乘法器返回
-12

可以这样写

def multiplier(*args)
  prod = recurse(*args.map(&:abs))
  args.count { |n| n < 0 }.even? ? prod : -prod
end

def recurse(first, *rest)
  first.zero? || rest.empty? ? first : ([recurse(*rest)]*first).sum
end

multiplier(3,  10,  4)        #=>  120
multiplier(3,  10,  4, 2, 3)  #=>  720
multiplier(3, -10,  4)        #=> -120
multiplier(3, -10, -4)        #=>  120
multiplier(3,   0,  4)        #=>    0
multiplier(3,   0, -4)        #=>    0
所以我们计算

([recurse(4)]*3).sum
在递归(4)中

由于
rest.empty#=>true
recurse
返回
first#=>4
,因此

([recurse(4)]*3).sum]
  #=> ([4]*3).sum => [4,4,4].sum => 12

返回到
乘数
。由于
[3,-4]
包含奇数个负值,乘法器返回
-12

我很困惑。。。
x*y*z
是否总能得到正确的解决方案?(顺便说一下,它与
x*(y*z)
相同)。。因为这似乎与你对变量的解释不一致。x*(y*z)总是会得到正确的答案。取代码中存在的变量。x:3,y:10,z:4=>3*(10*4)=>3*(40)=>120。你认为有什么不一致?好吧,我明白你的意思。我认为关键是你想在没有时间符号的情况下完成这项工作,也许你应该更明确地说明这是需求的一部分。我认为递归乘法总是没有时间符号。另外,我在问题的结尾做了评论,没有时间符号。我不知道为什么递归很重要,但我们可以避免使用时间符号,比如
Array.new(x,Array.new(y,z)).flatten.reduce(:+)
我很困惑。。。
x*y*z
是否总能得到正确的解决方案?(顺便说一下,它与
x*(y*z)
相同)。。因为这似乎与你对变量的解释不一致。x*(y*z)总是会得到正确的答案。取代码中存在的变量。x:3,y:10,z:4=>3*(10*4)=>3*(40)=>120。你认为有什么不一致?好吧,我明白你的意思。我认为关键是你想在没有时间符号的情况下完成这项工作,也许你应该更明确地说明这是需求的一部分。我认为递归乘法总是没有时间符号。另外,我在问题的结尾做了评论,没有时间符号。我不知道为什么递归很重要,但我们可以避免使用时间符号,比如
Array.new(x,Array.new(y,z)).flatten.reduce(:+)
谢谢。这对我个人来说太棒了,我会省略第6行中的
0
乘数(x,j,-1)
。当然,在功能上是一样的。我认为这个答案的关键点,你暗示过的,是这个函数是纯函数——也就是说,没有副作用,所以对于给定的输入,你总是会得到相同的结果——不像OP的原始版本,它操纵一个“全局”变量来累积结果。谢谢。这对我个人来说太棒了,我会省略第6行中的
0
乘数(x,j,-1)
。当然,在功能上是一样的。我认为这个答案的关键点,你暗示的,是这个功能是纯的,也就是说,没有副作用