我一直试图在Julia中为斐波那契函数做记忆.这就是我提出的.
原始未修改代码(用于控制目的)
function fib(x)
if x < 3
return 1
else
return fib(x-2) + fib(x-1)
end
end
Run Code Online (Sandbox Code Playgroud)
这是我的第一次尝试
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
Run Code Online (Sandbox Code Playgroud)
我的第二次尝试
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
Run Code Online (Sandbox Code Playgroud)
我的第三次尝试
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
Run Code Online (Sandbox Code Playgroud)
还有其他方法这样做我不知道吗?
Sim*_*rne 17
正如评论中指出的那样,Memoize.jl包当然是最简单的选择.这要求您在定义时标记方法.
到目前为止,最强大的方法是使用Cassette.jl,它允许您向预先存在的函数添加memoization,例如
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
Run Code Online (Sandbox Code Playgroud)
对正在发生的事情的一点描述:
MemoizeCtx 是我们正在定义的Cassette"上下文"overdub 运行而不是原始函数定义
recurse(...)告诉Cassette调用该函数,但忽略顶级overload.现在我们可以使用memoization运行该函数:
Cassette.overdub(MemoizeCtx(metadata=Dict{Int,Int}()), fib, 80)
Run Code Online (Sandbox Code Playgroud)
现在更酷的是我们可以使用一个现有的函数来调用fib,并记住对该函数fib 内部的调用:
function foo()
println("calling fib")
@show fib(80)
println("done.")
end
Cassette.overdub(MemoizeCtx(metadata=Dict{Int,Int}()), foo)
Run Code Online (Sandbox Code Playgroud)
(Cassette在编译器上仍然相当困难,所以这可能需要一段时间才能运行第一次,但之后会很快).
最简单的方法是使用 get!
const fibmem = Dict{Int,Int}()
function fib(n)
get!(fibmem, n) do
n < 3 ? 1 : fib(n-1) + fib(n-2)
end
end
Run Code Online (Sandbox Code Playgroud)
注意const外面的说明符fibmem。这避免了对的需求global,并使代码更快,因为它允许编译器在中使用类型推断fib。