我正试图在朱莉娅写一个Newton-Raphson求解器。 Newton-Raphson方法如图所示。
f(x) = x^2.5 - 3x^1.5 - 10
fprime(x) = 2.5x^1.5 - 4.5x^0.5
x = zeros(1000)
x[1] = 10
δ = 1 # a relatively large number compared to what we want the error to be
iter = 1
while δ > 1e-6
x[iter + 1] = x[iter] - f(x[iter])/fprime(x[iter])
iter += 1
δ = abs(x[iter] - x[iter + 1])
if iter == 100
break
end
end
println("The solution is ")
show(x[iter])
但是,当我运行代码时,我得到一个错误,说iter
没有定义,即使我在循环开始之前定义它。是否存在一些我完全不知道的范围问题?
ERROR: LoadError: UndefVarError: iter not defined
Stacktrace:
[1] top-level scope at /Users/natemcintosh/Documents/Julia/Learning_julia.jl:11 [inlined]
[2] top-level scope at ./none:0
[3] include_string(::Module, ::String, ::String) at ./loading.jl:1002
[4] (::getfield(Atom, Symbol("##120#125")){String,String,Module})() at /Users/natemcintosh/.julia/packages/Atom/Pab0Z/src/eval.jl:120
[5] withpath(::getfield(Atom, Symbol("##120#125")){String,String,Module}, ::String) at /Users/natemcintosh/.julia/packages/CodeTools/8CjYJ/src/utils.jl:30
[6] withpath at /Users/natemcintosh/.julia/packages/Atom/Pab0Z/src/eval.jl:46 [inlined]
[7] #119 at /Users/natemcintosh/.julia/packages/Atom/Pab0Z/src/eval.jl:117 [inlined]
[8] hideprompt(::getfield(Atom, Symbol("##119#124")){String,String,Module}) at /Users/natemcintosh/.julia/packages/Atom/Pab0Z/src/repl.jl:76
[9] macro expansion at /Users/natemcintosh/.julia/packages/Atom/Pab0Z/src/eval.jl:116 [inlined]
[10] (::getfield(Atom, Symbol("##118#123")){Dict{String,Any}})() at ./task.jl:85
in expression starting at /Users/natemcintosh/Documents/Julia/Learning_julia.jl:10
我已经尝试在x
循环的开头打印while
,它知道x
是什么,但认为iter
是未定义的。
首先让我给出解决方案:
有三种可能的方法
方法1.在global
之前加上iter += 1
并将其更改为global iter += 1
并且一切都会起作用(请注意以下关于δ
的评论 - 因为除非你在global
之前也预先加载δ = abs(x[iter] - x[iter + 1])
,否则它将无法正常工作,即代码将运行但会产生错误的结果 - 方法2和3没有这个问题)。
方法2.将代码包含在这样的函数中:
f(x) = x^2.5 - 3x^1.5 - 10
fprime(x) = 2.5x^1.5 - 4.5x^0.5
function sol(f, fprime)
x = zeros(1000)
x[1] = 10
δ = 1 # a relatively large number compared to what we want the error to be
iter = 1
while δ > 1e-6
x[iter + 1] = x[iter] - f(x[iter])/fprime(x[iter])
iter += 1
δ = abs(x[iter] - x[iter + 1])
if iter == 100
break
end
end
println("The solution is ")
show(x[iter])
end
sol(f, fprime) # now we call it
解决方案3.通过更改解决方案2中的行let
将代码包装在function sol(f, fprime)
块中,简单地说let
(您不需要再调用sol
)。
现在你必须这样做的原因。
在Julia 1.0中,while
引入了一个新的范围。 Julia 1.0中的范围规则是分配给while
循环内部的每个变量都被认为是局部变量(这已经改变,因为Julia 0.6区分了硬和软本地范围,在Julia 1.0中这种区别已经消失 - 所有本地范围都是相同)。
在代码中,您将值分配给两个变量:循环内的iter
和δ
。这意味着它们被Julia视为本地,因此在循环内分配值之前,不允许您访问它们的值。
您想要在iter
行中读取x[iter + 1] = x[iter] - f(x[iter])/fprime(x[iter])
,但仅在以下行中为其指定值。
至于δ
,事情更棘手。您为其分配值,但它在循环条件while δ > 1e-6
中使用。但是,此条件对外部作用域中定义的变量(原始情况下为全局)进行操作。所以一切都会起作用,但条件while δ > 1e-6
将始终看到δ
等于1
,因为它在循环之外查看变量的值。因此,这种情况永远不会触发(并且您将始终运行100次迭代)。总结一下,执行你想要的代码是什么(虽然如果你没有修复δ
赋值,你就不会收到警告):
f(x) = x^2.5 - 3x^1.5 - 10
fprime(x) = 2.5x^1.5 - 4.5x^0.5
x = zeros(1000)
x[1] = 10
δ = 1 # a relatively large number compared to what we want the error to be
iter = 1
while δ > 1e-6
x[iter + 1] = x[iter] - f(x[iter])/fprime(x[iter])
global iter += 1
global δ = abs(x[iter] - x[iter + 1])
if iter == 100
break
end
end
println("The solution is ")
show(x[iter])
最后请注意,即使行中有赋值,行x[iter + 1] = x[iter] - f(x[iter])/fprime(x[iter])
也能正常工作,因为你不会在其中重新绑定变量x
,而只更改数组中的一个元素(所以x
指向内存中的同一地址,而Julia将其视为一直是一个全局变量)。
你也许想在Julia手册中阅读这个https://docs.julialang.org/en/latest/manual/variables-and-scoping/或者这个问题的答案Julia Variable scope是类似的