在数值计算中,一维根查找算法用于求解形如f(x) = 0
的方程,其中f
是一个给定的函数,x
是一个实变量。本文将介绍几种常用的根查找算法,并探讨如何在C#中实现它们。
互联网上可以找到许多根查找算法及其源代码。工作主要是将这些算法翻译成C#,有时稍作修改,并将它们嵌入到一个方便的框架中,类似于C++的STL。
计算机如何求解f(x) = 0
这样的方程呢?根查找算法并不“解决”方程,而是通过迭代方法提供(在最佳情况下)一个近似解。算法从一个假定包含解的区间开始,每次迭代至少将区间长度减半(使用二分法)。当剩余区间的长度达到预定义值(称为精度)时,算法停止。
这种方法通常效果很好。但是,有时可能无法达到精度。为了防止算法无限迭代,应该在迭代次数达到某个值(称为迭代次数)时停止算法。
使用库非常简单。库提供了六种常用的方法,每种方法都嵌入在一个类中,该类继承自抽象的RootFinder
类。
如果有函数f
的导数表达式df
,可以使用牛顿-拉弗森方法。它是稳定的,并且收敛速度快。如果没有df
的表达式,答案就不那么容易了。实际上,这取决于对来说最重要的是什么。二分法总能给一个好近似,但不如其他方法快。三种方法:假位置法、割线法和里德法收敛更快,但在某些情况下可能会失败。布伦特方法似乎是最有效的方法。
假设想求解方程f(x) = 0
,其中f
定义如下:
private double f(double x) {
return 3 * x * x - 1;
}
两个解位于区间[-1; +1]。假设想要正根。别忘了算法只提供一个解。如果选择的起始区间太大,算法可能会出错,或者给出不想要的解。所以,应该从一个像[0; 1]这样的区间开始。
private double FindRoot(double x) {
// 创建包含算法的根查找对象
BisectionRootFinder finder = new BisectionRootFinder(new UnaryFunction(f));
// 定义想要的根的精度
finder.Accuracy = 1.0E-04;
// 防止溢出
finder.Iterations = 30;
// 无需外部括号计算
double root = finder.Solve(0.0, 1.0, false);
return root;
}
在[0;1]区间上的根r
是r = sqrt(1/3)
。精度确保算法提供的近似根r'
将满足:Abs(r'-r) < 10e-4 (Accuracy)
,除非算法达到了传递给它的最大迭代次数(这里是30次)。
如果有函数f
的导数表达式df
,使用牛顿-拉弗森方法。它是稳定的,并且收敛速度快。如果没有df
的表达式,答案就不那么容易了。实际上,这取决于对来说最重要的是什么。二分法总能给一个好近似,但不如其他方法快。三种方法:假位置法、割线法和里德法收敛更快,但在某些情况下可能会失败。布伦特方法似乎是最有效的方法。