唯一方便统一,本篇各算法均以这个最基本式子的来作例子
1.随机投点法(蒙特卡洛算法)
在求圆周率的文章中已经提及过一次此方法
在a到b和函数组成的矩形的范围内,随机投N个点,落到绿色阴影点的个数为M个,对于此图来说便可以容易得知积分的值(绿色阴影)为(M/N)*矩形面积。
代码清单:
public class JiFen {
public static void main(String[] args){
int N = 1000000;
int count = 0;
for(int i = 0; i < N; i++){
double x = Math.random();
double y = Math.random();
if(f(x) >= y)
count++;
}
System.out.println((double)count/N);
}
private static double f(double x) {
return x*x;
}
}
输出:0.333302
2.另一种蒙特卡洛法
第一种方法视乎情况比较特殊,如果是积分形式如下图:
对于普通情况,如果用第一种算法,就要判断随机点是投在了x轴的上方还是下方,对于矩形的选取还要分f(a),f(b)是否同号,以及f(a),f(b)的绝对值的大小,比较麻烦。
于是产生了另一种投点法:在a到b的范围内随机生成N个点x1~xn,则积分的值为(f(x1) + f(x2) + ...+ f(xn)) * (b-a)/m。
代码清单:
public class JiFen_toudian2 {
public static void main(String[] args){
double a = 0;
double b = 1;
double area = getArea(a,b);
System.out.println(area);
}
public static double getArea(double a, double b){
int sign = 1;//正负号标志位
if(a > b){
double t = a;
a = b;
b = t;
sign = -1;
}
int N = 10000;
double sum = 0;
for(int i = 0; i < N; i++){
double x = a + (b-a)*Math.random();//随机生成1个在(a,b)范围内的点
sum += f(x);
}
return (sum * (b-a)/N) * sign;
}
private static double f(double x) {
return x*x;
}
}
输出:0.33966325465503505
3.定义求积分法
回忆一下最初是怎么求积分的,是把一块面积分解成N个小矩形,然后求面积和,最后求极限。我们就利用这种方式来实现它,但我们的N毕竟有限,为了结果更准确,把求矩形面积改成求梯形面积(当然矩形也是可以的),如下图:
把(a,b)分成N等分,积分值等于S1+S2+....+Sn,其中Si = (f(xi) + f(x(i+1))) * (b-a)/n / 2(矩形面积公式)
有了之前的基础,就可以比较容易的写程序了。
代码清单:
public class JiFen3 {
/**
* @param args
*/
public static void main(String[] args) {
double a;
double b;
double y;
a = 0;
b = 1;
y = getArea(a, b);
System.out.println(y);
}
static double f(double x){
return x*x;
}
static double getArea(double a, double b){
int sign = 1;
if(a > b){
double t = a;
a = b;
b = t;
sign = -1;
}
double h;
double x;
double sum = 0;
int n = 10000;
h = Math.abs(a - b)/n;
x = a;
for(int i = 0; i < n; i++){
sum += f(x) + f(x + h);
x = x + h;
}
return sum * h / 2 * sign;
}
}
输出:0.3333333349999429
4.变步长梯形求积分法
用定义求积分法,要确定积分的误差是很难的,我们无法找到一个正好的N值符合我们要求的误差值,所以就需对定义法进行改进,改进的方式就是把原来固定的步长改为变化的步长,利用二分法,如下图:
图4-1
图4-2
图4-3
。
。
。
我们要分到什么时候呢? 分到 后一个面积和 - 前一个面积和 < 规定误差 时。这样我们就达到了精确的目的。
代码清单:
public class Jifen_bianchang {
static double e = 0.00001;// 误差
public static void main(String[] args) {
double a = 0;// 积分下限
double b = 1;// 积分上限
double area = getArea(a, b);
System.out.println(area);
}
public static double getArea(double a, double b) {
int sign = 1;// 正负标志位
if (a > b) {
double t = a;
a = b;
b = t;
sign = -1;
}
double s1 = 0;// 前一个面积和
double s2 = 0;// 后一个面积和
double h = b - a;
s2 = getOneArea(a, b, h);
for (int i = 2; Math.abs(s1 - s2) > e; i *= 2) {
double t = h / i;// 每个梯形高
double sum = 0;
double x = a;
for (int j = 0; j < i; j++) {// 求梯形和
sum += getOneArea(x, x + t, t);
x = x + t;
}
s1 = s2;
s2 = sum;
}
return sign * s2;
}
public static double getOneArea(double a, double b, double h) {
return (f(a) + f(b)) * h / 2;
}
public static double f(double x) {
return x * x;
}
}
输出:0.33333587646484375
积分算法(二)(未完待续)
积分算法(三)(未完待续)
积分算法(四)(未完待续)
==================================================================================================
作者:nash_ 欢迎转载,与人分享是进步的源泉!
转载请保留原文地址:http://blog.csdn.net/nash_/article/details/8560759
===================================================================================================