代码之家  ›  专栏  ›  技术社区  ›  natemcintosh

在while循环外部定义的变量没有在内部定义?

  •  1
  • natemcintosh  · 技术社区  · 6 年前

    我想在茱莉亚写一个牛顿-拉斐逊解算器。牛顿-拉夫逊法如图所示。

    Newton-Raphson solver equation

    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 是的,但是想 iter公司 未定义。

    1 回复  |  直到 6 年前
        1
  •  3
  •   Bogumił Kamiński    6 年前

    首先让我给出解决方案:

    有三种可能的方法

    global 之前 iter += 1 把它改成 global iter += 1 δ -因为它不会正常工作,除非你也预先准备好 全球的 之前 δ = abs(x[iter] - x[iter + 1])

    方法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。将代码包装在 let 换行阻塞 function sol(f, fprime) (你不需要打电话 sol

    现在是你必须这么做的原因。

    while 引入新范围。julia1.0中的作用域规则是 分配 进入一个 虽然 循环被认为是一个局部变量(这已经改变了,因为julia0.6区分了硬局部作用域和软局部作用域,在julia1.0中,这种区别已经消失了——所有的局部作用域都是相同的)。

    iter 在回路内部。这意味着Julia将它们视为本地的,因此在循环中为它们赋值之前,不允许访问它们的值。

    你想读书吗 iter公司 直列 x[iter + 1] = x[iter] - f(x[iter])/fprime(x[iter]) 但只能在下一行中为其赋值。

    至于 事情更棘手。给它赋值,但它在循环条件中使用 while δ > 1e-6 . 但是,此条件对外部范围中定义的变量起作用(在原始情况下是全局的)。所以一切都会好的,但条件 而>1e-6 我会一直看到的 等于 1 δ 作业(您不会收到警告):

    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 指向内存中的同一地址,Julia一直将其视为全局变量)。

    https://docs.julialang.org/en/latest/manual/variables-and-scoping/ 或者这个问题的答案 Julia Variable scope 是相似的