当前位置 主页 > 服务器问题 > Linux/apache问题 >

    Apache Commons Math3学习之数值积分实例代码

    栏目:Linux/apache问题 时间:2019-10-13 23:53

    Apache.Commons.Math3里面的数值积分支持类采用的是“逼近法”,即,先对大区间做一次积分,再对小区间做一次积分,若两次积分结果的差值小于某一设定的误差值,则认为积分完成。否则,将区间再次细分,对细分后的区间进行积分,与前一次积分相比较,如此反复迭代,直至最近的两次积分差值足够小。这样的结果,有可能会导致无法收敛。

    为了使用org.apache.commons.math3.analysis.integration包中的积分器类,需要先实现UnivariateFunction接口(本文以MyFunction为例),实现其value方法。然后创建指定的积分器对象,本文以SimpsonIntegrator为例,最后调用其integrate(...)方法即可算出MyFunction的积分。

    调用integrate(...)方法时需要提供4个参数:

    第1个是最大逼近次数,要适当大一些,否则可能会无法收敛;
    第2个是MyFunction类的实例;
    第3个是积分区间下限;
    第4个是积分区间上限。

    SimpsonIntegrator在第一次迭代时一定是分别以积分下限和积分上限作为x调用连词MyFunction.value(...)方法,下一次则会将区间分成2份(除上下限x值之外,还有一个中间x值),再下一次则是分成4份……

    以下是使用辛普森积分类的例子:

    import java.util.ArrayList;
    import java.util.List;
    import org.apache.commons.math3.analysis.UnivariateFunction;
    import org.apache.commons.math3.analysis.integration.SimpsonIntegrator;
    import org.apache.commons.math3.analysis.integration.UnivariateIntegrator;
    interface TestCase 
    {
    	public Object run(List<Object> params) throws Exception;
    	public List<Object> getParams();
    	public void printResult(Object result) throws Exception;
    }
    public class TimeCostCalculator 
    {
    	public TimeCostCalculator() 
    	  {
    	}
    	/** 
      * 计算指定对象的运行时间开销。 
      * 
      * @param testCase 指定被测对象。 
      * @return 返回sub.run的时间开销,单位为s。 
      * @throws Exception 
      */
    	private double calcTimeCost(TestCase testCase) throws Exception 
    	  {
    		List<Object> params = testCase.getParams();
    		long startTime = System.nanoTime();
    		Object result = testCase.run(params);
    		long stopTime = System.nanoTime();
    		testCase.printResult(result);
    		double timeCost = (stopTime - startTime) * 1.0e-9;
    		return timeCost;
    	}
    	public void runTest(TestCase testCase) throws Exception 
    	  {
    		double timeCost = calcTimeCost(testCase);
    		System.out.println("时间开销:: " + timeCost + "s");
    		System.out.println("-------------------------------------------------------------------------------");
    	}
    	public static void main(String[] args) throws Exception 
    	  {
    		TimeCostCalculator tcc = new TimeCostCalculator();
    		tcc.runTest(new CalcSimpsonIntegrator());
    	}
    }
    /** 
     * 使用辛普森法求解数值积分。Apache.Common.Math3中所用的辛普森法是采用逼近法,即先对整个积分区间用矩形积分,然后将区间分解为4份,再次积分,比较两次积分的差值,若想对误差大于某个预订数值, 
     * 则认为还需要继续细分区间,因此会将区间以2倍再次细分后求积分,并将结果与前一次积分的结果比较,直至差值小于指定的误差,就停止。 
     * @author kingfox 
     * 
     */
    class CalcSimpsonIntegrator implements TestCase 
    {
    	public CalcSimpsonIntegrator() 
    	  {
    		System.out.print("本算例用于测试使用辛普森法计算积分。正在初始化计算数据 ... ...");
    		inputData = new double[arrayLength];
    		for (int index = 0; index < inputData.length; index++)  // 鏂滃潯鍑芥暟 
    		{
    			inputData[index] = Math.sin(2 * Math.PI * index * MyFunction.factor * 4);
    		}
    		func = new MyFunction();
    		integrator = new SimpsonIntegrator();
    		System.out.println("初始化完成!");
    	}
    	@Override 
    	  public Object run(List<Object> params) throws Exception 
    	  {
    		double result = ((SimpsonIntegrator)(params.get(1))).integrate(steps, (UnivariateFunction)(params.get(0)), lower, upper);
    		return result;
    	}
    	/** 
      * 获取运行参数 
      * @return List对象,第一个元素是求积函数,第二个参数是积分器。 
      */
    	@Override 
    	  public List<Object> getParams() 
    	  {
    		List<Object> params = new ArrayList<Object>();
    		params.add(func);
    		params.add(integrator);
    		return params;
    	}
    	@Override 
    	  public void printResult(Object result) throws Exception 
    	  {
    		System.out.println(">>> integration value: " + result);
    	}
    	UnivariateFunction func = null;
    	UnivariateIntegrator integrator = null;
    	class MyFunction implements UnivariateFunction 
    	  {
    		@Override 
    		   public double value(double x) 
    		   {
    			//     double y = x * factor;   // 1. 
    			//     double y = 4.0 * x * x * x - 3.0 * x * x + 2.0 * x - 1.0;  // 2. 
    			//     double y = -1.0 * Math.sin(x) + 2.0 * Math.cos(x) - 3.0;   // 3. 
    			double y = inputData[(int)(x / factor)];
    			// 4. 
    			//     System.out.println(x + ", " + y); 
    			return y;
    		}
    		private static final double factor = 0.0001;
    	}
    	private double[] inputData = null;
    	private static final int arrayLength = 5000;
    	private static final double lower = 0.0;
    	//  private static final double upper = 2.0 * Math.PI;   // 3. 
    	private static final double upper = (arrayLength - 1) * MyFunction.factor;
    	// 1. 2. 4. 
    	private static final int steps = 1000000;
    }