ruby中的递归乘法器
我正在尝试用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
@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)
。当然,在功能上是一样的。我认为这个答案的关键点,你暗示的,是这个功能是纯的,也就是说,没有副作用