看其他篇章到目錄選擇。
函數方程求解,其實是函數的零點問題,也就是說函數的曲線與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