看其他篇章到目录选择。
函数方程求解,其实是函数的零点问题,也就是说函数的曲线与X轴的交点。对于线性方程,我们可以轻易的求解,对于线性方程组,利用前面讲过的的矩阵分解方法也可以求解。那么对于函数表达的很多非线性方程的求解。我们要依赖数值算法。Commons Math包中专门有一个analysis.solver包来解决这个问题。
Analysis.solver包中有一个基本接口类——UnivariateRealSolver,其中定义了一系列接口方法,最重要的方法就是double solve(UnivariateRealFunction f, double min, double max)了。很明显,这个方法的参数是函数的表达式以及求解的区间范围,返回值是函数在区间内的一个零值点。
Solver包中的这些类的组织结构形式与积分中的类似,结构类图如下:
具体的求解算法有很多,solver包中也实现了很多算法,包括对分法、牛顿法等。我们这里以这两个算法的实现为例,看看该如何使用这个包中的接口方法。待求解的函数仍以正弦函数为例。
1
/** *//**
2
*
3
*/
4
package algorithm.math;
5
6
import org.apache.commons.math.ConvergenceException;
7
import org.apache.commons.math.FunctionEvaluationException;
8
import org.apache.commons.math.analysis.UnivariateRealFunction;
9
import org.apache.commons.math.analysis.solvers.BisectionSolver;
10
import org.apache.commons.math.analysis.solvers.UnivariateRealSolver;
11
import org.apache.commons.math.analysis.solvers.UnivariateRealSolverFactory;
12
import org.apache.commons.math.analysis.solvers.UnivariateRealSolverFactoryImpl;
13
14
/** *//**
15
* @author Jia Yu
16
* @date 2010-11-24
17
*/
18
public class SolverTest
{
19
20
/** *//**
21
* @param args
22
*/
23
public static void main(String[] args)
{
24
// TODO Auto-generated method stub
25
solver();
26
factorySolver();
27
}
28
29
private static void factorySolver()
{
30
// TODO Auto-generated method stub
31
UnivariateRealFunction f = new SinFunction();
32
UnivariateRealSolverFactory factory=new UnivariateRealSolverFactoryImpl();
33
UnivariateRealSolver solver = factory.newNewtonSolver();
34
try
{
35
System.out.println("NewtonSolver : sin(x)=0 when x from -1 to 1, x = "+ solver.solve(f, -1, 1));
36
} catch (ConvergenceException e)
{
37
// TODO Auto-generated catch block
38
e.printStackTrace();
39
} catch (FunctionEvaluationException e)
{
40
// TODO Auto-generated catch block
41
e.printStackTrace();
42
}
43
}
44
45
private static void solver()
{
46
// TODO Auto-generated method stub
47
UnivariateRealFunction f = new SinFunction();
48
UnivariateRealSolver solver = new BisectionSolver();
49
try
{
50
System.out.println("BisectionSolver : sin(x)=0 when x from 3 to 4, x = "+ solver.solve(f, 3, 4));
51
} catch (ConvergenceException e)
{
52
// TODO Auto-generated catch block
53
e.printStackTrace();
54
} catch (FunctionEvaluationException e)
{
55
// TODO Auto-generated catch block
56
e.printStackTrace();
57
}
58
}
59
60
}
61
输出结果:
BisectionSolver : sin(x)=0 when x from 3 to 4, x = 3.141592502593994
NewtonSolver : sin(x)=0 when x from -1 to 1, x = 0.0
可以看到,程序都输出了正确的结果。但是,其实还是可以尝试一些复杂的参数来测试算法的,这里就不再多说,不妨看看牛顿法在(-1,4)区间的效果。
不管是哪种方法,其实都是要设定误差限的,默认的是10E-6。
一个小的建议是使用工厂模式的构建方法,因为毕竟这个包内提供了工厂的实现,那为什么不用这种更灵活的方式呢?
写了方程求解的例子,就不要再问什么求平方根的牛顿法或者立方根什么的问题了,不就是x^n-R=0的方程嘛,设定区间[0,+∞]就可以了。原理明白,其他的问题都很好解决,不是吗?
相关资料:
对分法:http://mathworld.wolfram.com/Bisection.html
牛顿法:http://mathworld.wolfram.com/NewtonsMethod.html
Commons math包:http://commons.apache.org/math/index.html