如何在不使用任何宏的情况下停止 Julia 中的循环并同时打印 ErrorMsg?

How to halt a loop in Julia and printing the ErrorMsg at the same time without using any macros?

我正在写一个简单的牛顿法

x_(n+1) = x_n - f(x_n) / f_prime(x_n)

求二次函数的根(可以是实数或复数):

f(x) = a*x*x + b*x + c

abc给定常数,均为实数)。我知道如果循环中的起点或某个迭代点的导数为零,则牛顿法将失败。我想在 for/while 循环中使用 if 语句来避免这种情况。 Julia 在 Fortran 中有类似 stop 0 的语法吗?

通用牛顿法求根代码:

function newton_root_finding(f, f_diff, x0, rtol=1e-8, atol=1e-8)
    f_x0 = f(x0)
    f_diff_x0 = f_diff(x0)
    x1 = x0 - f_x0 / f_diff_x0
    f_diff_x1 = f_diff(x1)

    @assert abs(f_diff_x0) > atol + rtol * abs(f_diff_x0) "Zero derivative. No solution found."

    while abs(f_x0) > atol + rtol * (abs(f_x0))
        x0 = x1
        f_x0 = f(x0)
        f_diff_x0 = f_diff(x0)
        x1 = x0 - f_x0 / f_diff_x0
    end

    return x1
end 

function quadratic_func(x)
    a = 1.0
    b = 0.0 
    c = 2.0
    return a*x*x + b*x + c
end

function quadratic_func_diff(x)
    a = 1.0
    b = 0.0 
    c = 2.0   
    return 2.0*a*x + 1.0*b + 0.0*c

end

newton_root_finding(quadratic_func, quadratic_func_diff, 1.0 + 0.5im)

在上面的代码中,我使用了 @assert 宏来实现它,但我不想使用任何宏。我想在我的 while 循环中使用 if 语句来停止它。我注意到的另一件事是,如果我更改为 @assert abs(f_diff_x0) != 0,此测试将被忽略。 "zero derivative" 不完全等于 0 是因为一些舍入错误吗?

要解决您的第一个问题,您可以使用 break 退出 while 循环,例如

function test()
    i = 0
    while true
        i += 1
        if i > 10
            break
        end
    end
    return i
end

关于您的第二个问题,在比较浮点数时,通常最好使用 isapprox(如果您与零进行比较,请提供 atol)而不是 ==!=.

从循环内部退出的方式一般是break语句; a return 实现相同的目的,因为它只是退出整个函数。

您可以使用 Base.isapprox(x, y; atol=atol, rtol=rtol) 进行比较。它的文档开头为:

Inexact equality comparison: true if norm(x-y) <= max(atol, rtol*max(norm(x), norm(y))).

norm 退回到 abs 的数字。而且我认为您可能在这两个比较中都有一个错误,总是将 x0 处的值与其自身进行比较。

至于零导数的突破,我认为@assert在这里是合适的:如果你得到零导数,你不会停止迭代和return结果,但是你抛出错误以表示不可行的条件。因此,我会按如下方式编写您的函数:

function newton_root_finding(f, ∂f, x0, rtol=1e-8, atol=1e-8)
    x_old = x0
    y_old = f(x0)

    while true
        df_old = ∂f(x_old)
        @assert !isapprox(df_old, 0, rtol=rtol, atol=atol) "Zero derivative. No solution found."

        x_new = x_old - y_old / df_old
        y_new = f(x_new)

        isapprox(y_old, y_new, rtol=rtol, atol=atol) && return x_new

        x_old, y_old = x_new, y_new
    end
end 

这个 returns 3.357392012620626e-26 + 1.4142135623730951im 在你的测试用例上,大约 sqrt(2)im