我正在尝试用Julia写一个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
是不确定的。
答案 0 :(得分:2)
首先让我给出解决方案:
有三种可能的方法
方法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
,而只更改数组的一个元素(所以{{ 1}}指向内存中的同一地址,Julia始终将其视为全局变量。
另外,您可能想阅读Julia手册中的https://docs.julialang.org/en/latest/manual/variables-and-scoping/或这个问题的答案Julia Variable scope相似