2026a

# 标量函数的根


# 对一元非线性方程求解

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。