修订 #3
我正在尝试使用原始的 3-arg 模型函数在 Ruby 中开发 Ackermann。我这样做的尝试似乎显示了 memoize'd 版本 - ack比原始版本花费更长的时间 -原始- 所以显然“某事”是错误的:
1% ruby -v
ruby 2.0.0p648 (2015-12-16 revision 53162) [universal.x86_64-darwin16]
1% time ruby ackermann3.rb raw silent
raw 0.107u 0.023s 0:00.13 92.3% 0+0k 0+0io 0pf+0w
1% time ruby ackermann3.rb ack silent
ack 0.563u 0.049s 0:00.62 96.7% 0+0k 0+0io 0pf+0w
对于这个模块 Ackermann3.rb
##
# https://www.saylor.org/site/wp-content/uploads/2013/04/Ackermann-Function.pdf
#
# Ackermann's original three-argument function: ƒ(m,n,p) is
# defined recursively as follows for nonnegative integers m, n, and p:
#
# ƒ(m,n,0) = m + n
# ƒ(m,0,1) = 0
# ƒ(m,0,2) = 1
# ƒ(m,0,p) = m for p > 2
# ƒ(m,n,p) = ƒ(m, ƒ(m,n - 1,p), p - 1) for n > 0 and p > 0
#
# Usage: ruby ./ackerman3.rb raw | ack
#
# RUBY_THREAD_VM_STACK_SIZE 10M
##
fun = ARGV[0]
if fun.nil?
puts "Usage: ruby ./ackermann3.rb {ack | raw} [silent]"
exit 1
end
log = ARGV[1]
if log.nil?
silent = false
elsif 'silent'.match(log.downcase)
silent = true
else
silent = false
end
def is_number? string
true if Float(string) rescue false
end
def filesize(string_size)
units = ['B', 'K', 'M', 'G', 'T', 'P', 'E']
size = Float(string_size)
return '0b' if size == 0
exp = (Math.log(size) / Math.log(1024)).to_i
exp = 6 if exp > 6
bits = '%.1f' % [size.to_f / 1024 ** exp]
if "#{bits}".end_with? ".0"
bits['.0'] = ''
end
'%s%s' % [bits, units[exp]]
end
stk = ENV['RUBY_THREAD_VM_STACK_SIZE']
if stk.nil?
stk = "undef stk"
elsif is_number?(stk)
stk = "EOF " + filesize(stk)
end
def ack(m, n, p)
@results ||= {}
@results[[m,n,p]] ||= begin
if p == 0
m + n
elsif n == 0 && p > 2
m
elsif n == 0 && p > 0
p - 1
else
ack(m, ack(m,n - 1,p), p - 1)
end
end
end
def raw(m, n, p)
if p == 0
m + n
elsif n == 0 && p > 2
m
elsif n == 0 && p > 0
p - 1
else
raw(m, raw(m,n - 1,p), p - 1)
end
end
9.times do |m|
9.times do |n|
9.times do |p|
if (m+n+p) < 9
print "#{fun} (#{m}, #{n}, #{p}) => " unless silent
begin
result = Object.send(fun, m, n, p)
rescue SystemStackError
#yoink
result = stk
end
puts "#{result}" unless silent
end
end
end
end
print "#{fun} " if silent
修改了脚本以解决先前的评论 - 我遇到的错误,但我不明白为什么记忆的变体无效。