# 标量函数的根
# 对一元非线性方程求解
fzero 函数尝试求一个一元方程的根。可以通过用于指定起始区间的单元素起点或双元素向量调用该函数。如果为 fzero 提供起点 x0,fzero 将首先搜索函数更改符号的点周围的区间。如果找到该区间,fzero 返回函数更改符号的位置附近的值。如果未找到此类区间,fzero 返回 NaN。或者,如果知道函数值的符号不同的两个点,可以使用双元素向量指定该起始区间;fzero 保证缩小该区间并返回符号更改处附近的值。
以下部分包含两个示例,用于说明如何使用起始区间和起点查找函数的零元素。下图显示了 humps 的图。
using TyMath
using TyPlot
using TyOptimization
function humps(x=0:0.05:1)
y = @. 1 / ((x - 0.3)^2 + 0.01) + 1 / ((x - 0.9)^2 + 0.04) - 6
return x, y
end
x = -1:0.01:2;
_, y = humps(x);
plot(x, y)
xlabel("x");
ylabel("humps(x)")
grid("on")
# 为 fzero 设置选项
可以通过设置选项控制 fzero 函数的多个方面。使用 optimset 设置选项。选项包括:
选择 fzero 生成的显示量;
选择控制 fzero 如何确定它得到根的不同公差;
选择用于观察 fzero 逼近根的进度的绘图函数;
使用自定义编程的输出函数观察 fzero 逼近根的进度。
# 使用起始区间
humps 的图指示 x = -1 时函数为负数,x = 1 时函数为正数。可以通过计算这两点的 humps 进行确认。
humps(1)[2]
ans = 16.0
humps(-1)[2]
ans = -5.137792103142627
因此,可以将 [-1 1] 用作 fzero 的起始区间。
fzero 的迭代算法可求 [-1 1] 越来越小的子区间。对于每个子区间,humps 在两个端点的符号不同。由于子区间的端点彼此越来越近,因此它们收敛到 humps 的零位置。
要显示 fzero 在每个迭代过程中的进度,请使用 optimset 函数将 Display 选项设置为 iter。
options = optimset(; Display="iter");
然后如下所示调用 fzero:
a, = fzero(x -> humps(x)[2], [-1, 1], options)
Func-count x f(x) Procedure
2 -1 -5.137792103142627 initial
3 -0.5138761817627325 -4.0223522478484295 interpolation
4 -0.5138761817627325 -4.0223522478484295 bisection
5 -0.4736349718877958 -3.8376689684679426 interpolation
6 -0.115286531384581 0.4144414231890732 bisection
7 -0.115286531384581 0.4144414231890732 interpolation
8 -0.1325624790061304 -0.022690660697188392 interpolation
9 -0.13166571878158242 -0.0011492038721838682 interpolation
10 -0.13161801028192072 1.883714633166278e-7 interpolation
11 -0.1316180181007658 -2.793498765640834e-11 interpolation
12 -0.13161801809960644 8.881784197001252e-16 interpolation
13 -0.13161801809960644 8.881784197001252e-16 interpolation
Zero found in the interval [-1, 1]
(-0.13161801809960644, 8.881784197001252e-16, 1, intervaliterations: 0
iterations: 11
funcCount: 13
algorithm: bisection, interpolation
message: Zero found in the interval [-1, 1])
a = -0.13161801809960644
每个值 x 代表迄今为止最佳的端点。Procedure 列向您显示每步的算法是使用对分还是插值。
可以通过输入以下内容验证 a 中的函数值是否接近零:
humps(a)[2]
ans = 8.881784197001252e-16
# 起点的使用
假定您不知道 humps 的函数值符号不同的两点。在这种情况下,可以选择标量 x0 作为 fzero 的起点。fzero 先搜索函数更改符号的点附近的区间。如果 fzero 找到此类区间,它会继续执行上一部分中介绍的算法。如果未找到此类区间,fzero 返回 NaN。
例如,将起点设置为 -0.2,将 Display 选项设置为 Iter,并调用 fzero:
options = optimset(; Display="iter");
a, = fzero(x -> humps(x)[2], -0.2, options)
Search for an interval around -0.2 containing a sign change:
Func-count a f(a) b f(b) Procedure
1 -0.2 -1.3538461538461544 -0.2 -1.3538461538461544initial interval
3 -0.19434314575050762 -1.260774267924175 -0.2056568542494924 -1.4441053187263329search
Search for a zero in the interval [-0.19434314575050762, -0.2056568542494924]:
5 -0.192 -1.2213708604044413 -0.20800000000000002 -1.480695004118668search
Search for a zero in the interval [-0.192, -0.20800000000000002]:
7 -0.18868629150101524 -1.1647701907847354 -0.2113137084989848 -1.5316652244980977search
Search for a zero in the interval [-0.18868629150101524, -0.2113137084989848]:
9 -0.184 -1.0829274223349206 -0.21600000000000003 -1.6022350624128503search
Search for a zero in the interval [-0.184, -0.21600000000000003]:
11 -0.1773725830020305 -0.9634552235080811 -0.22262741699796953 -1.6991131748724024search
Search for a zero in the interval [-0.1773725830020305, -0.22262741699796953]:
13 -0.16799999999999998 -0.7866356652478839 -0.23200000000000004 -1.8305508797150143search
Search for a zero in the interval [-0.16799999999999998, -0.23200000000000004]:
15 -0.15474516600406094 -0.5196200015120827 -0.2452548339959391 -2.0060218318504393search
Search for a zero in the interval [-0.15474516600406094, -0.2452548339959391]:
17 -0.13599999999999995 -0.10416513532638216 -0.26400000000000007 -2.2352122527053093search
Search for a zero in the interval [-0.13599999999999995, -0.26400000000000007]:
18 -0.10949033200812185 0.5722455847597159 -0.26400000000000007 -2.2352122527053093search
Func-count x f(x) Procedure
18 -0.10949033200812185 0.5722455847597159 initial
19 -0.1409841176426295 -0.21927656600614132 interpolation
20 -0.1322593470752026 -0.015422419571262225 interpolation
21 -0.13161660403278272 3.407287157575212e-5 interpolation
22 -0.13161802091964897 -6.795048257401959e-8 interpolation
23 -0.13161801809961884 -2.984279490192421e-13 interpolation
24 -0.13161801809960647 8.881784197001252e-16 interpolation
25 -0.13161801809960647 8.881784197001252e-16 interpolation
Zero found in the interval [-0.10949033200812185, -0.26400000000000007]
(-0.13161801809960647, 8.881784197001252e-16, 1, intervaliterations: 9
iterations: 7
funcCount: 25
algorithm: bisection, interpolation
message: Zero found in the interval [-0.10949033200812185, -0.26400000000000007])
a = -0.13161801809960647
每个迭代中当前子区间的端点列在标题 a 和 b 下,而端点处的相应 humps 值分别列在 f(a) 和 f(b) 下。
注意:端点 a 和 b 未按任何特定顺序列出:a 可能大于 b 或小于 b。
对于前 9 步,humps 的符号在当前子区间的两端点都为负号,如输出中所示。在第 10 步,humps 的符号在 a (-0.10949) 处为正号,但在 b (-0.264) 处为负号。从该点开始,如上一部分中所述,算法继续缩小区间 [-0.10949 -0.264],直到它达到值 -0.1316。