算法简介:p325
就是最常见的划分小区间,求单个小区间的面积,再累加。
唯一的不同就是计算机没办法控制分成的区间个数,所以我们通过设置精度的方法来控制程序二分的次数,从而简介达到划分足够大的小区间的目的。
程序设计分析:
1.待解决的问题一:函数值的计算,求那个理想矩形面积不仅需要区间长度来近似成为矩形的宽,还需要函数值来近似成矩形的高。
2.待解决的问题二:积分的实现(实际上就是累加外加一个精度判断)
1.问题一的解决办法:设置一个求函数的类
2.问题二的解决办法:设置一个求积分的类
统筹:采取分文件编写和纯虚函数的抽象类。 设立两个类族,一个是求函数值的函数解析式的类族。一个是用来求积分但是算法不同的类族。 (这样的目的是如果有新的函数解析式,直接编写一个新的函数子类即可,如果有新的算法,也是直接编写一个积分算法子类即可,极大的增强了程序的可扩展性。)
代码实现:
举例:求下面这个积分
//file1.h
#ifndef _FILE1_H
#define _FILE1_H
//函数解析式类族的定义,这里只写了一个解析式的类来便于说明,实际使用的时候可以根据需要加
class function {
public:
virtual double operator()(double x)const = 0; //()的重载,使其具有求函数值的功能,因为平常我们不是习惯用f()来求值嘛,这样省事,你想想,如果再写写一个函数,调用的时候又得一大串,很麻烦。
virtual ~function() {}; //虚析构,如果下面的子类涉及到堆区内存开辟,就派生用场了。
};
class my_function :public function {
public:
double operator()(double x)const;
};
//积分求解的算法类族定义,这里也是以上面介绍的算法为例,如果有新的算法,也可以直接建一个my_intergation1等等来完成扩展。
class intergation {
public:
virtual double operator()(double a, double b, double eps)const = 0;
virtual ~intergation() {};
};
class my_intergation :public intergation{
const function& f;
public:
my_intergation(const function& f) :f(f){}
virtual double operator()(double a, double b, double eps)const;
};
#endif
//file1的实现
#include<iostream>
#include"file1.h"
#include<cmath>
using namespace std;
//返回带入x求解后的函数值,直接借助()的重载来实现,不用再编写一个函数来实现,极大的简化了书写的效率,很精妙的一步。
double my_function::operator()(double x)const {
return log(1.0 + x) / (1.0 + x * x);
}
//积分算法类的实现。
double my_intergation::operator()(double a, double b, double eps)const {
bool done = false;
int n = 1;
double h = b - a;
double tn = h * (f(a) + f(b)) / 2;
double t2n;
do {
double sum = 0;
for (int i = 0; i < n; i++) {
double x = a + (i + 0.5) * h;
sum += f(x);
}
t2n = (tn + h * sum) / 2.0;
if (fabs(t2n - tn) < eps) {
done = true;
}
else
{
tn = t2n;
n *= 2;
h /= 2;
}
} while (!done);
return t2n;
}
//主函数cpp
#include<iostream>
#include"file1.h"
#include<iomanip>
using namespace std;
int main() {
my_function f;
my_intergation trazp(f); //注意:这里的trazp后面的()和下面的那句话里的()不一样,这个是拿f来初始化my_intergation类的对象trazp,下面那个是重载后的(),相当于调用了名字为()的函数,编译器根据参数列表来判断改用哪个,我们只需写好参数列表就行。
cout << setprecision(8) << trazp(0, 2, 1e-7) << endl;
}