【数学】用C语言实现函数的定积分—— 把 “定积分定义计算出的值” 和 “牛顿-莱布尼兹公式计算出的值” 两者进行误差比较

因为考研数学看到定积分的定义以及“牛顿-莱布尼兹公式”

突然心血来潮,想用C语言把它们实现出来并对比。

1.用 ”定积分定义“ 计算得出数值 以及 ”牛顿-莱布尼兹公式(微积分基本定理)计算得出数值 的差异。

2.用 "定积分定义" 积分,”分段点“数量越多趋向于无穷个时

   ——即n越大,趋向于无穷的时候,用 "定积分定义" 积出来的数值,会越接近积分范围内图形的真实面积。

   (默认用微积分基本定理得出的面积是真实的,微积分基本定理微分中值定理 严谨证明得出。)


一、公式说明

定积分定义:

将[a,b]区间段,分为n份区间,那么就有n-1个分段点。

1. 每份区间长度为:                            gif.latex?%5Cfrac%7Bb-a%7D%7Bn%7D%20%3D%5CDelta%20x           ——        共有n份

2. 分段点集合:                                  A = [x_1, ..., x_{n-1}]

3. 各个相邻分段点之间的数值关系:  x_i = x_{i-1} + \Delta x, x_{i}, x_{i-1} \in A

4. 每一份区间上的面积 gif.latex?%5Csmall%20S_i:               gif.latex?%5Csmall%20%5C%5CS_1%3Df%28x_1%29%5Ccdot%20%5CDelta%20x%20%5C%5CS_2%3Df%28x_2%29%5Ccdot%20%5CDelta%20x%20%5C%5C...%20%5C%5CS_n%3Df%28x_n%29%5Ccdot%20%5CDelta%20x

5. 最终,定积分的定义:                   gif.latex?%5Csmall%20%5Cint%20%5Ea_b%20f%28x%29%20dx%3D%5Clim_%7Bn%20%5Cto%20%5Cinfty%7D%5Csum%20%5En_%7Bi%3D1%7DS_i%3D%20%5Clim_%7Bn%20%5Cto%20%5Cinfty%7D%20%5Csum%20%5En_%7Bi%3D1%7Df%28x_i%29%5Ccdot%20%5CDelta%20x

   或者:                                             gif.latex?%5Csmall%20%5Cint%20%5Ea_b%20f%28x%29dx%20%3D%20%5Clim_%7Bn%20%5Cto%20%5Cinfty%7D%20%5Csum%20%5En_%7Bi%3D1%7Df%28i%5Ccdot%20%5Cfrac%7Bb-a%7D%7Bn%7D%29%5Ccdot%20%5Cfrac%7Bb-a%7D%7Bn%7D

   (我们要用这个来写程序表示用定积分定义求积分)


牛顿-莱布尼兹公式(微积分基本定理):

 gif.latex?%5Cint%5Ea_bf%28x%29dx%3DF%28a%29-F%28b%29


二、理论转化成代码

以 gif.latex?%5Csmall%20%5Cint%5Ea_b%20f%28x%29dx%20%3D%20%5Cint%5Ea_b%20%5Cfrac%7B1%7D%7Bx%281+x%5E2%29%7Ddx 为例(因为朋友问我这一题解法)


1. 用 牛顿-莱布尼兹公式 进行求解 

先必须先求出原函数,再代入a和b。

过程:1.拆分分母、2.分别各自求解原函数、3.分别代入上下限a与b计算,最终求得 f(x)x∈[a,b] 上的积分。

gif.latex?%5Csmall%20f%28x%29%20%3D%20%5Cfrac%7B1%7D%7Bx%7D%20-%20%5Cfrac%7Bx%7D%7B1+x%5E2%7D

gif.latex?%5Csmall%20%5C%5C%20F%28x%29%20%3D%20%5Cint%20f%28x%29%5C%2Cdx

gif.latex?%5Csmall%20%5C%5C%3D%20%5Cint%20%5Cfrac%7B1%7D%7Bx%7D%5C%2Cdx%20-%20%5Cint%20%5Cfrac%7Bx%7D%7B1+x%5E2%7D%5C%2Cdx

gif.latex?%5Csmall%20%5C%5C%20%3D%20%5Cint%20%5Cfrac%7B1%7D%7Bx%7D%5C%2C%20dx%20-%20%5Cfrac%7B1%7D%7B2%7D%5Ccdot%20%5Cint%20%5Cfrac%7B1%7D%7B1+x%5E2%7D%5C%2Cd%281+x%5E2%29

gif.latex?%5Csmall%20%5C%5C%20%5Ctherefore%20%5C%2CF%28x%29%20%3Dln%5C%2Cx%20-%20%5Cfrac%7B1%7D%7B2%7D%5Ccdot%20ln%5C%2C%281+x%5E2%29

所以 S = F(a) - F(b)

所以用牛顿-莱布尼兹公式求解函数的代码可以写成:

#include
#include

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<


2. 用 定积分定义 进行求解 

手算算不了算这么多次,而计算机可以帮助做大量的运算。

(题外话:通常纸上计算不会用这种方法,在考试里面一般只会作为一个选择题考大家对 定积分定义 的熟悉度)

gif.latex?%5Csmall%20%5Cint%20%5Ea_b%20f%28x%29%20dx%3D%20%5Clim_%7Bn%20%5Cto%20%5Cinfty%7D%20%5Csum%20%5En_%7Bi%3D1%7Df%28i%5Ccdot%20%5Cfrac%7Bb-a%7D%7Bn%7D%29%5Ccdot%20%5Cfrac%7Bb-a%7D%7Bn%7D

变量设定:

我们计算时,忽略gif.latex?%5Csmall%20n%20%5Cto%20%5Cinfty,将n作为一个参数,类型为int。

n可以自由设定数值,不过n越大,算出来面积越接近真实值。

gif.latex?%5Csmall%20%5Csum%20%5En_%7Bi%3D1%7D:     一个循环,从i = 1到 i = n,设一个变量i,类型为int。

a 和 b: 设置为两个变量,类型为int。

gif.latex?%5Csmall%20%5Cfrac%7Bb-a%7D%7Bn%7D:  出现2次,把这个赋予一个变量c,使gif.latex?%5Csmall%20c%20%3D%20%5Cfrac%7Bb-a%7D%7Bn%7D,变量c类型为double。

s1:      用来存放计算出的面积的值,类型为double。

函数指针:

pA:作为指向函数的指针(称为函数指针),若使用"定积分定义"(函数S),在参数列表。

传入参数为 ”pA=函数g(x)“,那在函数S内调用pA的过程中,就会指向调用g(x)函数。

若传入参数为"pA=函数f(x)",则在S内调用pA的过程中,就会指向调用f(x)函数。

(用函数指针好处就是:函数S内即将调用的"函数"不用写死,即将调用的“函数”可以作为参数传入)

#include

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<


三、"牛顿-莱布尼兹公式" 和 "定积分定义" 分别求出的数值对比

上完整代码: 

#include 
#include 
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) <

结果如图:

【数学】用C语言实现函数的定积分—— 把 “定积分定义计算出的值” 和 “牛顿-莱布尼兹公式计算出的值” 两者进行误差比较_第1张图片

可以看出,用定积分定义求面积,当n越大时,误差越小。

你可能感兴趣的:(c语言,微积分)