我一直试图用朱莉娅(Julia)的斐波那契功能进行记忆。这就是我想出的。
未经修改的原始代码(出于控制目的)
function fib(x)
if x < 3
return 1
else
return fib(x-2) + fib(x-1)
end
end
这是我的第一次尝试
memory=Dict()
function memfib(x)
global memory
if haskey(memory,x)
return memory[x]
else
if x < 3
return memory[x] = 1
else
return memory[x] = memfib(x-2) + memfib(x-1)
end
end
end
我的第二次尝试
memory=Dict()
function membetafib(x)
global memory
return haskey(memory,x) ? memory[x] : x < 3 ? memory[x]=1 : memory[x] = membetafib(x-2) + membetafib(x-1)
end
我的第三次尝试
memory=Dict()
function memgammafib!(memory,x)
return haskey(memory,x) ? memory[x] : x < 3 ? memory[x]=1 : memory[x] = memgammafib!(memory,x-2) + memgammafib!(memory,x-1)
end
还有其他我不知道的方法吗?
答案 0 :(得分:14)
正如评论中指出的那样,Memoize.jl软件包无疑是最简单的选择。这要求您在定义时标记该方法。
但是,到目前为止,最强大的方法是使用Cassette.jl,它使您可以将备忘录添加到预先存在的功能中,例如
fib(x) = x < 3 ? 1 : fib(x-2) + fib(x-1)
using Cassette
Cassette.@context MemoizeCtx
function Cassette.overdub(ctx::MemoizeCtx, ::typeof(fib), x)
get(ctx.metadata, x) do
result = recurse(ctx, fib, x)
ctx.metadata[x] = result
return result
end
end
对正在发生的事情的一些描述:
MemoizeCtx
是我们正在定义的盒式磁带“上下文” overdub
而不是原始函数定义
recurse(...)
告诉Cassette调用该函数,但忽略顶级overload
。现在我们可以通过备忘录运行该功能
Cassette.overdub(MemoizeCtx(metadata=Dict{Int,Int}()), fib, 80)
现在更酷的是,我们可以采用一个调用fib
的现有函数,并在该函数的内部 中记住对fib
的调用:
function foo()
println("calling fib")
@show fib(80)
println("done.")
end
Cassette.overdub(MemoizeCtx(metadata=Dict{Int,Int}()), foo)
(盒式磁带在编译器上仍然相当困难,因此第一次运行可能需要一段时间,但之后会很快)。
答案 1 :(得分:5)
最简单的方法是使用get!
const fibmem = Dict{Int,Int}()
function fib(n)
get!(fibmem, n) do
n < 3 ? 1 : fib(n-1) + fib(n-2)
end
end
请注意fibmem
之外的const
指定符。这样可以避免使用global
,并且可以使代码更快,因为它允许编译器在fib
中使用类型推断。
答案 2 :(得分:1)
由于函数的参数是整数,因此可以使用简单的数组,该数组的速度比Dict
快(请确保在高速缓存中为大参数使用BigInt
s以避免溢出) ):
function fib(n, cache=sizehint!(BigInt[0,1],n))
n < length(cache) && return cache[n+1]
f = fib(n-1,cache) + fib(n-2,cache)
push!(cache,f)
return f
end