梯形递推的变步长求积公式虽然算法简单,但精度低,收敛的速度慢,因此,研究收敛速度快、精度高的龙贝格算法显得尤为重要。
例:用龙贝格算法求f(x) = sin(x) / x 在区间[0,1]的数值积分,精度要求为1e-6.
- 加工流程:
- 程序框图设计:
- 运行示例:
- 源码:
#include<iostream>
#include<cmath>
double f(double x); //自定义函数
using namespace std;
int main(void)
{
double a, b, accuracy; //a为区间下限,b为区间上限,accuracy为精度
cout << "请输入积分区间:"; //输入提示
cin >> a >> b;
cout << "请输入精度:"; //输入提示
cin >> accuracy;
double h; //步长
h = b - a;
double T1, T2; //T1:二分前的梯形法积分值;T2:二分后的梯形法积分值;
T1 = h / 2 * (1 + f(b));
T2 = 0;
int k = 1; //记录二分次数
cout << "T" << pow(2, 0) << " = " << T1 << endl;
double S1, S2; //对T1与T2加权平均,得辛普森积分值
double C1, C2; //对S1与S2加权平均,得柯特斯积分值
double R1, R2; //对C1,C2加权平均,得龙贝格积分值
int flag = 1; //flag作为循环控制标志性变量
while (flag == 1)
{
double sum = 0; //各分点的函数值和
double x = a + h / 2; //分点值
while (x < b) //在区间上限范围内求各分点的函数值和
{
sum += f(x);
x += h;
}
T2 = T1 / 2 + h / 2 * sum; //计算梯形序列得下一个二分结果
cout << "T" << pow(2, k) << " = " << T2 << endl;
S2 = T2 + 1.0 / 3 * (T2 - T1); //线性组合外推值simpson
cout << "S" << pow(2, k - 1) << " = " << S2 << endl;
if (k == 1) //至少外推2次得出S1,S2
{
k++;
h /= 2;
T1 = T2;
S1 = S2;
continue;
}
else
{
C2 = S2 + 1.0 / 15 * (S2 - S1); //线性组合外推值Cotes
cout << "C" << pow(2, k - 2) << " = " << C2 << endl;
if (k == 2) //至少外推3次得出C1,C2
{
C1 = C2;
k++;
h /= 2;
T1 = T2;
S1 = S2;
continue;
}
else
{
R2 = C2 + 1.0 / 63 * (C2 - C1); //线性组合外推至Romberg
cout << "R" << pow(2, k - 3) << " = " << R2 << endl;
if (k == 3) //至少外推4次得出R1,R2
{
R1 = R2;
C1 = C2;
k++;
h /= 2;
T1 = T2;
S1 = S2;
continue;
}
else if (abs(R2 - R1) >= accuracy) //精度仍然不符合要求,继续二分步长、继续外推
{
R1 = R2;
C1 = C2;
k = k + 1;
h = h / 2;
T1 = T2;
S1 = S2;
}
else //精度符合要求,修改flag为0,跳出while循环
{
flag = 0;
cout << "Romber算法求得数值积分结果为:" << R2 << endl;
}
}
}
}
return 0;
}
double f(double x) //自定义被积函数
{
double result;
result = sin(x) / x;
return result;
}