用C语言实现定积分计算(包括无穷积分/可自定义精度)

关于严谨性的声明:

在用C语言进行定积分的计算之前,我需要声明以下几点:

一、我们所进行定积分计算的函数都是应当是黎曼可积的,这保证了我们即使均匀地分割区间也保证了积分的收敛性。

二、我们同时还应该认识到,鉴于某些函数不一定是在每一点上都是可导的,因此我们将不使用所谓的利用到导数来提高计算精度的这种算法。

三、考虑到某些函数并不是连续的,如果涉及到这些计算,那么我们计算到的结果将会是一个瑕积分,如果这个瑕积分是收敛的,那么我们得到的就是收敛值。如果不收敛,这个瑕积分的值并不是积分主值,因为我们没有办法保证瑕点附近的两个点的趋近于瑕点的趋势是一样的。

四、如果你计算的是一个无穷积分,如果这个无穷积分是收敛的,那么我们得到的就是收敛值。如果不收敛,那么我们得到的值将会是它的积分主值。


另外,考虑到C语言精度的限制,我们无需写一个专门的程序用来计算瑕积分,因为当我们用C语言计算这个瑕积分的时候,就相当于我们采用了两边趋近瑕点取极限的办法来计算瑕积分,当然了,由于我们采用了均匀分割的方法,所以当我们两边趋近的时候并不能使得其以任意方式趋近瑕点。除此之外,你应当保证瑕点不在积分区间的边界上。对于无穷积分,不论我们怎么切割区间都不能使得划分的区间足够小,除非我们划分区间的时候将他划为了无穷份,当然了这个划分的份数应当是无穷积分区间大小的高阶无穷大。事实上,这是做不到的,因此我们将采用函数变换的方法将无穷积分转化为有限积分。

最后,鉴于C语言的精度限制,如果我们只是计算性质较为良好的函数,那么我们将会获得非常好的精度,甚至是仅仅只是可测的函数,也是可以计算的。但如果我们计算的是有着许多无穷间断点,或有着许多瑕点的函数,或者是震荡很厉害的函数,那么它的积分值误差将会较大。最后我还想声明一点,那就是我们不应该用该程序去计算本身就是发散的积分因为你甚至可能得到的仅仅只是个有限值。


1. 有限积分

根据我们在之前所说的,我们可以轻易得到:

4876ac26b780492fa8be38d3a18643af.png

 其中:

af0e38abe5074924a2496a1f9e8b34c5.png

 因此,我们不难写出以下代码:

//定义一个C语言函数,用于进行微积分的数值运算
long double integrate(long double a, long double b, long int n)
{long double s = 0;long double dx = (b - a) / n;for (long int i = 1; i < n; i++){s += f(a + i * dx) * dx;}return s;
}

其中函数 long double integrate(long double a, long double b, long int n) 就是用来计算定积分的函数。值得注意的是,在调用该函数之前,我们应当提前定义被积函数f(x)。其中a,b,n分别为积分下限,积分上限和区间分割数。

以上是矩形法,数值计算的精度并不是非常高,我们改进一下,使用梯形法,得到:

2b8d53cf63924c3abcfe887ddc7511f3.png

  其中:

af0e38abe5074924a2496a1f9e8b34c5.png

  因此,我们不难写出以下代码:

long double integral(long double x0, long double xt, long long n)
{long double sum = 0;long double dx = (xt - x0) / n;for (long long k = 0; k < n; k++){sum += ((f(x0 + k * dx) + f(x0 + (k + 1) * dx)) / 2) * dx;}return sum;
}

相较于矩形法,梯形法不论是精度还是速度都有着不小的提升。


2. 无穷积分

我们已经讨论过无穷积分采用直接计算的困难的地方,因此我们将采用函数变换的方法。

我们很容易注意到:

fc7ab638fa94417cbfd96d1a8366f04c.png

 

4b9f1397223e403983affb661e6d0c29.png

这两个式子是等价的,因此我们可以将所有的无穷积分转化为无限积分。只需要利用积分区间的可叠加性即可。因此不多叙述。


 

有了相关的理论铺垫后,我们添加一点点细节。以下直接给出关于定积分的计算代码:(详细信息在注释里)

#include <stdio.h>  
#include <math.h>  #define inf INFINITY// 定义用于被积分的函数  
long double f(long double x) 
{return exp(x);
}// 定义被积函数的特殊形式用于计算无穷积分  
long double g(long double x) 
{long double y = 1.0 / x;long double result = f(y) * (1.0 / (x * x));return result;
}// 一个用于计算定积分的C语言子程序
//值得注意的是我们还将数学函数作为参数传给了这个函数,这可以让我们有多个数学函数时,可以指定数学函数计算  
long double integral(long double x0, long double xt, long long n, long double (*f)(long double)) 
{//对于黎曼可积的函数,这样的积分值为零,直接返回。if ((x0 == xt)&&((x0 != INFINITY && x0 != -INFINITY)&&(xt != INFINITY && xt != -INFINITY)))return 0;else{long double sum = 0;long double dx = (xt - x0) / n; for (long long k = 0; k < n; k++){sum += ((f(x0 + k * dx) + f(x0 + (k + 1) * dx)) / 2) * dx;}return sum;}
}// 定义绝对值函数  
static long double lfabs(long double x) 
{if (x >= 0)return x;elsereturn -x;
}//用于计算指定精度的定积分的函数
//值得注意的是我们还将数学函数作为参数传给了这个函数,这可以让我们有多个数学函数时,可以指定数学函数计算  
long double definite_integral(long double x0, long double xt, long double esp, long double (*f)(long double)) 
{//如果积分限不是无穷则进行经典数值积分计算if ((x0 != INFINITY && x0 != -INFINITY) && (xt != INFINITY && xt != -INFINITY)) {long long i = 10;  long double d = 0;long double s = 0;do {long double s1 = integral(x0, xt, i, f);long double s2 = integral(x0, xt, 10 * i, f);i *= 10;s = s2;d = lfabs(s1 - s2);} while (d > esp);return s;}//如果是无穷积分,则采用特殊方法进行数值计算else {//积分下限有限大小//值得注意的是,当我们使用g函数进行积分的时候,有一个积分限迎丹是0,然而事实上我们以一个很小的小数来替代if (x0 != INFINITY && x0 != -INFINITY){if (xt == INFINITY){long double s1 = definite_integral(x0, 1, esp, f);long double s2 = definite_integral(esp/1000000.0, 1, esp, g);return (s1 + s2);}else if (xt == -INFINITY){long double s1 = definite_integral(-1, x0, esp, f);long double s2 = definite_integral(-1, -esp/1000000.0, esp, g);return -(s1 + s2);}}//积分上限有限大小else if (xt != INFINITY && xt != -INFINITY){if (x0 == INFINITY){long double s1 = definite_integral(xt, 1, esp, f);long double s2 = definite_integral(esp/1000000.0, 1, esp, g);return -(s1 + s2);}else if (x0 == -INFINITY){long double s1 = definite_integral(-1, xt, esp, f);long double s2 = definite_integral(-1, -esp/1000000.0, esp, g);return (s1 + s2);}}//积分上下限都为无穷else if (x0 == -INFINITY && xt == INFINITY){long double s1 = definite_integral(-1, 1, esp, f);long double s2 = definite_integral(-1, -esp/1000000.0, esp, g);long double s3 = definite_integral(esp/1000000.0, 1, esp, g);return (s1 + s2 + s3);}else if (x0 == INFINITY && xt == -INFINITY){long double s1 = definite_integral(-1, 1, esp, f);long double s2 = definite_integral(-1, -esp/1000000.0, esp, g);long double s3 = definite_integral(esp/1000000.0, 1, esp, g);return -(s1 + s2 + s3);}//如果积分是从正无穷积分到正无穷或从负无穷积分到负无穷则需要另外判断else{if (x0 == INFINITY && xt == INFINITY){if (f(INFINITY) == 0)return 0;elsereturn NAN;}else if (x0 == -INFINITY && xt == -INFINITY){if (f(-INFINITY) == 0)return 0;elsereturn NAN;}}return NAN;}
}int main() 
{long double x0, xt, esp;printf("如果要输入无穷大或无穷小,请输入inf或-inf\n");printf("请输入积分区域(x0,xt),和最大容忍误差esp:>>");scanf("%lf %lf %lf", &x0, &xt, &esp);long double result = definite_integral(x0, xt, esp, &f);printf("%.16lf\n", result);return 0;
}

在计算指定定积分精度的C函数中,对于无穷积分我们通过转化为有限积分后再调用自身的方式有效地减伤了大量大代码量。这也是为什么要把我们定义的数学函数作为参数传给函数的原因。

如下:

c94ba1cf189e45c69bc20fd96075e074.png

 


代码的运行:

3ffd0c7a889343b6a048668e63298a06.png

 我们指定数学函数为exp(x),可以看到我们很好地计算出来该无穷积分。

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/59909.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

stm32 cubemx can通讯(1)回环模式

文章目录 前言一、cubemx配置二、代码1.过滤器的配置&#xff08;后续会介绍&#xff09;2.main.c3.主循环 总结 前言 介绍使用stm32cubemx来配置can&#xff0c;本节讲解一个简答&#xff0c;不需要stm32的can和外部连接&#xff0c;直接可以用于验证的回环模式。 所谓回环模…

《golang设计模式》第二部分·结构型模式-01-适配器模式(Adapter)

文章目录 1. 概念1.1 角色1.2 应用场景1.2 类图 2. 代码示例2.1 设计2.2 代码2.3 示例类图 1. 概念 定义一个适配器&#xff0c;帮助原本不能实现接口的类“实现”该接口 1.1 角色 目标&#xff08;Target&#xff09;&#xff1a;客户端调用的目标接口 被适配者&#xff08…

【kubeadm的配置安装】

目录 一、环境准备二、所有节点安装docker三、部署K8S集群1、查看镜像2、初始化kubeadm方法一&#xff1a;1、修改配置文件2、在线拉取镜像3、初始化 master 方法二、 3、设定kubectl4、所有节点部署网络插件flannel 四、部署 Dashboard1、在 master01 节点上操作 master&#…

韩顺平Linux基础篇

一、课程内容 二、Linux应用领域 一、Linux使用在哪些地方 Linux最强应用&#xff1a;服务器 三、Linux概述 三、Linux和Unix的关系 五、VM和Linux的安装 基本说明 学习Linux需要一个环境&#xff0c;我们需要创建一个虚拟机&#xff0c;然后再虚拟机上安装一个Centos系统来学…

dirsearch_暴力扫描网页结构

python3 dirsearch 暴力扫描网页结构&#xff08;包括网页中的目录和文件&#xff09; 下载地址&#xff1a;https://gitee.com/xiaozhu2022/dirsearch/repository/archive/master.zip 下载解压后&#xff0c;在dirsearch.py文件窗口&#xff0c;打开终端&#xff08;任务栏…

web-初始前端

不区分大小写&#xff0c;单双引号&#xff0c; <html><head><title>初识HTML</title></head><body><h1>Hello world!</h1><img src OIF-C.jfif/></body> </html> <!-- 文件格式 --> <!DOCTYPE h…

【雕爷学编程】Arduino动手做(199)---8x32位WS2812B全彩屏模块7

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…

使用 `nmcli` 在 CentOS 8 上添加永久路由

CentOS 8 使用 NetworkManager 作为默认的网络管理工具&#xff0c;因此我们可以使用 nmcli 工具来实现相同的目标。使用 nmcli 可以更加直观地管理路由&#xff0c;并且更符合 CentOS 8 的默认网络管理方式。 以下是使用 nmcli 在 CentOS 8 上添加永久路由的步骤&#xff1a;…

Spring中的AOP

Spring中的AOP 一.Spring AOP的概念 1.AOP的概述 AOP的全称是Aspect Oriented Programming&#xff0c;即面向切面编程。是通过预编译方式和运行期间动态代理&#xff0c;实现程序功能的统一维护的一种技术。AOP是OOP面向对象编程的一种延续。 使用OOP编程时&#xff0c;虽然…

模板学堂|SQL数据集动态参数使用场景及功能详解

DataEase开源数据可视化分析平台于2022年6月正式发布模板市场&#xff08;https&#xff1a;//dataease.io/templates/&#xff09;。模板市场旨在为DataEase用户提供专业、美观、拿来即用的仪表板模板&#xff0c;方便用户根据自身的业务需求和使用场景选择对应的仪表板模板&a…

后端进阶之路——Spring Security构建强大的身份验证和授权系统(四)

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★前端炫酷代码分享 ★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ 解决算法&#xff0c;一个专栏就够了★ ★ 架…

【C语言】操作符详解

目录 一、算数操作符 二、移位操作符 1.左移操作符 2.右移操作符 (1) 逻辑右移 (2) 算术右移 (3)小总结 三、位操作符 四、赋值操作符 五、单目操作符 六、关系操作符 七、逻辑操作符 八、 条件操作符 九、逗号表达式 十、下标引用、函数调用和结构成员 1. [ ]下…