如何在不使用任何宏的情况下停止 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
(a
、b
、c
给定常数,均为实数)。我知道如果循环中的起点或某个迭代点的导数为零,则牛顿法将失败。我想在 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
。
我正在写一个简单的牛顿法
x_(n+1) = x_n - f(x_n) / f_prime(x_n)
求二次函数的根(可以是实数或复数):
f(x) = a*x*x + b*x + c
(a
、b
、c
给定常数,均为实数)。我知道如果循环中的起点或某个迭代点的导数为零,则牛顿法将失败。我想在 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
ifnorm(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
。