因为考研数学看到定积分的定义以及“牛顿-莱布尼兹公式”
突然心血来潮,想用C语言把它们实现出来并对比。
1.用 ”定积分定义“ 计算得出数值 以及 ”牛顿-莱布尼兹公式“ (微积分基本定理)计算得出数值 的差异。
2.用 "定积分定义" 积分,”分段点“数量越多趋向于无穷个时
——即n越大,趋向于无穷的时候,用 "定积分定义" 积出来的数值,会越接近积分范围内图形的真实面积。
(默认用微积分基本定理得出的面积是真实的,微积分基本定理 由 微分中值定理 严谨证明得出。)
一、公式说明
定积分定义:
将[a,b]区间段,分为n份区间,那么就有n-1个分段点。
1. 每份区间长度为: —— 共有n份
2. 分段点集合:
3. 各个相邻分段点之间的数值关系:
4. 每一份区间上的面积 :
5. 最终,定积分的定义:
或者:
(我们要用这个来写程序表示用定积分定义求积分)
牛顿-莱布尼兹公式(微积分基本定理):
二、理论转化成代码
以 为例(因为朋友问我这一题解法):
1. 用 牛顿-莱布尼兹公式 进行求解
先必须先求出原函数,再代入a和b。
过程:1.拆分分母、2.分别各自求解原函数、3.分别代入上下限a与b计算,最终求得 f(x) 在 x∈[a,b] 上的积分。
所以 S = F(a) - F(b)
所以用牛顿-莱布尼兹公式求解函数的代码可以写成:
#include<iostream>
#include<math.h>
using namespace std;
//F(x):由f(x)用不定积分推导出
double F(double x){
//x^2写法不行,要用x*x
return (log(x) - log(1.000 + x*x)/2);
}
//调用求面积,以在区间[2,6]积分为例, (double)s为得出的面积
int main(){
double s = F(6) - F(2);
cout<<s<<endl;
return 0;
}
2. 用 定积分定义 进行求解
手算算不了算这么多次,而计算机可以帮助做大量的运算。
(题外话:通常纸上计算不会用这种方法,在考试里面一般只会作为一个选择题考大家对 定积分定义 的熟悉度)
变量设定:
我们计算时,忽略,将n作为一个参数,类型为int。
n可以自由设定数值,不过n越大,算出来面积越接近真实值。
: 一个循环,从i = 1到 i = n,设一个变量i,类型为int。
a 和 b: 设置为两个变量,类型为int。
: 出现2次,把这个赋予一个变量c,使
,变量c类型为double。
s1: 用来存放计算出的面积的值,类型为double。
函数指针:
pA:作为指向函数的指针(称为函数指针),若使用"定积分定义"(函数S),在参数列表。
传入参数为 ”pA=函数g(x)“,那在函数S内调用pA的过程中,就会指向调用g(x)函数。
若传入参数为"pA=函数f(x)",则在S内调用pA的过程中,就会指向调用f(x)函数。
(用函数指针好处就是:函数S内即将调用的"函数"不用写死,即将调用的“函数”可以作为参数传入)
#include<iostream>
using namespace std;
//f(x)函数
double f(double x){
return 1/(x*(1+x*x));
}
//参数1. n:将区间a到b分成n份,当n越大,趋于正无穷时,求出的数值越接近真实面积
//参数2、3. a、b:分别为积分下、上限,积分区间是从小到大:a到b
//参数4. pA:使用 函数指针 传入函数
//使用函数指针,可以在 "这个函数S(...)" 的参数列表传入 "想要使用的函数" 的首地址
//在 "这个函数" 里面调用pA(...)就相当于调用在参数里面传入的 "想要使用的函数"
double S(int n, double b, double a, double (*pA)(double)){
//int n=1000; //将b-a分成n份
double c = (b-a)/n; //每份是(b-a)/n
double s1 = 0.0; //存放面积累加值
//循环计算矩形面积近似曲边梯形面积
//pA(a+i*c)*c 代表 f(xi)*Δx
for(long i = 1; i < n; i++){
//pA(传入double类型参数) = f(A)
s1 += pA(a+i*c)*c;
}
return s1;
}
void main(){
//表示用定积分定义求函数f(x),在x∈[2,6]的面积
//将[2,6]区间分成10000份,可以尝试设置更大的值,精度会更高
//“f”表示调用函数f(x)
cout<<S(10000,6,2,f)<<endl;
}
三、"牛顿-莱布尼兹公式" 和 "定积分定义" 分别求出的数值对比
上完整代码:
#include <iostream>
#include <math.h>
using namespace std;
double F(double x);
double f(double x);
double a(float n, double b, double a, double (*pA)(double));
//F(x)
double F(double x){
//x^2写法不行,要用x*x
return (log(x) - log(1.000 + x*x)/2);
}
//f(x)函数
double f(double x){
return 1/(x*(1+x*x));
}
//积分区间是从小到大:a到b
//使用 函数指针 传入函数
double s(int n, double b, double a, double (*pA)(double)){
//int n = 1000; //将b-a分成n份
double c = (b-a)/n; //每份是(b-a)/n
double s1 = 0.0; //存放面积累加值
//循环计算矩形面积近似曲边梯形面积
for(long i = 1; i < n; i++){
s1 += pA(a+i*c)*c;
}
return s1;
}
int main () {
//求f(x) = 1/x(1+x^2) 在x属于[1,2]的面积/积分
//1.用牛顿-莱布尼兹公式
//F(x) = lnx - ln(1+x^2);
cout.setf(ios::fixed);
cout.precision(12);
double a1 = F(6) - F(2);
cout << "牛顿-莱布尼兹公式求得:"<< F(6) - F(2) <<endl<<endl<<endl;
//2.定积分定义
for(int i = 1; i < 6; i++){
//double n = 1000*pow(10,i);
int n = int(float(1000*pow(100,i)));
double a2 = s(n,6,2,f);
cout << right <<"定积分定义(n="<<n<<")求得:" <<a2<<endl;
cout << "与牛顿公式差值:" << a2 - a1 << endl << endl;
}
/*
double a3 = a(10000,6,2,f);
cout << right << "定积分定义(n=10000)求得:" <<a3<<endl;
cout<<"与牛顿公式差值:"<<a3-a1<<endl<<endl;
double a4 = a(100000,6,2,f);
cout << right << "定积分定义(n=100000)求得:" <<a4<<endl;
cout<<"与牛顿公式差值:"<<a4-a1<<endl<<endl;
double a5 = a(1000000,6,2,f);
cout << right << "定积分定义(n=1000000)求得:" <<a5<<endl;
cout<<"与牛顿公式差值:"<<a5-a1<<endl<<endl;
double a6 = a(10000000,6,2,f);
cout << right << "定积分定义(n=10000000)求得:" <<a6<<endl;
cout<<"与牛顿公式差值:"<<a6-a1<<endl<<endl; */
return 0;
}
结果如图:
可以看出,用定积分定义求面积,当n越大时,误差越小。