正如大家所说,不可能提供一个通用的算法来找到所有或一些根(其中一些大于一)。一些是多少根?通常,您无法找到所有根,因为许多函数将具有无限多个根。
即使像牛顿这样的方法也不总是收敛到一个解决方案。我倾向于喜欢一种好的、相当稳定的方法,它会在合理的情况下收敛到一个解决方案,例如一个已知函数会改变符号的括号。您可以找到这样的代码,它在单根上具有良好的收敛行为,但在函数表现不佳时仍然受到保护,基本上类似于二等分方案。
所以,给定一个不错的求根方案,你可以尝试一些简单的事情,比如通货紧缩。因此,考虑一个简单的函数,例如第一类 Bessel 函数。我将使用 MATLAB 完成所有示例,但是任何具有稳定编写良好的 rootfinder(如 MATLAB 中的 fzero)的工具就足够了。
ezplot(@(x) besselj(0,x),[0,10])
grid on

f0 = @(x) besselj(0,x);
xroots(1) = fzero(f0,1)
xroots =
2.4048
从图中,我们可以看到在 5 或 6 附近有第二个根。
现在,为该根缩小 f0,创建一个基于 f0 的新函数,但该函数在 xroots(1) 处缺少根。
f1 = @(x) f0(x)./(x-xroots(1));
ezplot(f1,[0,10])
grid on

请注意,在这条曲线中,f0 在 xroots(1) 处的根现在已被删除,就好像它不存在一样。我们能找到第二个根吗?
xroots(2) = fzero(f1,2)
xroots =
2.4048 5.5201
我们当然可以继续,但在某些时候这个方案会因为数值问题而失败。而且这种失败也不会花费太长时间。
更好的方案可能是(对于一维问题)使用括号方案,结合抽样方法。我说得更好,因为它不需要修改初始函数来放气根。(对于 2-d 或更高版本,事情当然会变得更加复杂。)
xlist = (0:1:10)';
flist = f0(xlist);
[xlist,flist]
ans =
0 1.0000
1.0000 0.7652
2.0000 0.2239
3.0000 -0.2601
4.0000 -0.3971
5.0000 -0.1776
6.0000 0.1506
7.0000 0.3001
8.0000 0.1717
9.0000 -0.0903
10.0000 -0.2459
如您所见,该函数在区间 [2,3]、[5,6] 和 [8,9] 中具有符号变化。可以在括号中搜索的 rootfinder 将在这里进行。
fzero(f0,[2,3])
ans =
2.4048
fzero(f0,[5,6])
ans =
5.5201
fzero(f0,[8,9])
ans =
8.6537
只需查找符号更改,然后将已知括号放入根查找器。这将提供尽可能多的解决方案,您可以找到括号。
请注意,上述方案存在严重问题。它将完全找不到像 f(x)=x^2 这样的简单函数的双根,因为不存在符号变化。如果您选择的采样过于粗略,那么您可能会有一个包含两个根的区间,但您不会在端点处看到符号变化。
例如,考虑函数 f(x) = x^2-x,它在 0 和 1 处有单根。但是如果你在 -1 和 2 处对该函数进行采样,你会发现它在两个点上都是正的。没有符号变化,但有两个根。
同样,没有任何方法可以做到完美。您总是可以设计一个会导致任何此类数值方法失败的函数。