算法基本原理:把原区间分为一系列小期间(n份),在每个小区间上都用小的梯形面积来近似代替原函数的积分,当小区间足够小时,就可以得到原来积分的近似值。但是这个过程中有一个问题是步长的取值,步长太大精度难以保证,步长太小会导致计算量的增加,所以,实际计算中常常采用变步长的方法,使得在步长逐次减小的过程中,求得的积分结果满足要求的精度为止。
首先,给出两个计算公式
(1) //计算步长为h的积分
(2) //将步长h二分,计算以h/2为步长的积分
步骤:
- 取n=1,利用公式(1)计算积分值
- 进行二分,利用新的公式(2)计算新的积分值
- 进行判断,如果两次计算积分值的差在给定的误差范围之内,二分后的积分值就是所需的结果,计算结束,否则返回第二步继续运行
因此,主要计算的问题有两个
一. 被积函数值的运算(设置Function类)
二. 变步长梯形积分的实现(设置Trapz类)
#ifndef _TRAPZINT_H_
#define _TRAPZINT_H_
class Function{
public:
virtual double operator()(double x) const = 0;//纯虚函数重载运算符()
virtual ~Function(){}//析构函数
};
class MyFunction :public Function{
public:
virtual double operator()(double x) const;//覆盖虚函数
};
class Integration{//抽象类Integration的定义
public:
virtual double operator()(double a, double b, double eps) const = 0;
virtual ~Integration(){}
};
class Trapz :public Integration{//公有派生类Trapz的定义
public:
Trapz(const Function &f) :f(f){}//构造函数
virtual double operator()(double a, double b, double eps) const;//覆盖虚函数
private:
const Function &f;//私有成员,Function类对象的指针
};
#endif
#include"Trapzint.h"
#include<iostream>
#include<cmath>
using namespace std;
//计算被积函数的函数值
double MyFunction::operator()(double x) const{
return log(1.0 + x) / (1.0 + x*x);
}
//积分运算过程,重载为运算符()
double Trapz::operator()(double a, double b, double eps) const{
//计算区间[a,b]之间误差在eps之内的积分值
bool done = false;//Trapz类的虚函数成员
int n = 1;
double h = b - a;
double tn = h*(f(a) + f(b)) / 2;//计算n=1时的积分
double t2n;//步长为一半的时候的积分值
do{
double sum = 0;
for (int k = 0; k < n; k++){
double x = a + (k + 0.5)*h;
sum += f(x);
}
t2n = (tn + h*sum) / 2.0;//利用公式(2)计算积分
if (fabs(tn - t2n) < eps)
done = true;//判断积分误差
else{
tn = t2n;
n *= 2;
h /= 2;
}
} while (!done);
return t2n;
}
#include"Trapzint.h"
#include<iostream>
#include<iomanip>
using namespace std;
int main(){
MyFunction f;//定义MyFunction类的对象
Trapz trapz(f);//定义Trapz类的对象
//计算并输出结果
cout << "Trapz Int:" << setprecision(7) << trapz(0, 2, 1e-7) << endl;
return 0;
}
结果