`
helloyesyes
  • 浏览: 1334006 次
  • 性别: Icon_minigender_2
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

GP技术的展望——C--

阅读更多
GP技术的展望——C--
莫华枫

C++的复杂是公认的,尽管我认为在人类的聪明智慧之下,这点复杂压根儿算不上什么。不过我得承认,对于一般的应用而言,C++对程序员产生的压力还是不 小的。毕竟现在有更多更合适的选择。仅仅承认复杂,这没有什么意义。我不时地产生一个念头:有什么办法既保留C++的优点,而消除它的缺点和复杂。我知道 D语言在做这样的事情。但是,D更多地是在就事论事地消除C++的缺陷,而没有在根本上消除缺陷和复杂性。
一般而言,一样东西复杂了,基本上都是因为东西太多。很显然,C++的语言特性在众多语言中是数一数二的。于是,我便想到或许把C++变成“C--”,可以治好C++的复杂之病。在探讨这个问题之前,让我们先从C出发,看看C++为何如此复杂。

C和C++

尽管存在这样那样的不足,比如non-lalr的语法、隐式的指针类型转换等,但C语言的设计哲学却是足够经典的。C语言有一个非正式的分类,认为它既非汇编这样的低级语言,也非Pascal那样的高级语言, 而应该算作中级语言,介于其他两类语言之间。这种分类恰如其分地点出了C语言的特点和理念:以高级语言语法形式承载了低级语言的编程模型。低级语言的特点 是可以直接地描述硬件系统的结构。C则继承了这个特点。C语言直观地反映了硬件的逻辑构造,比如数组是内存块,可以等价于指针。在C语言中,我们可以几乎 直接看到硬件的构造,并且加以操作。这些特性对于底层开发至关重要。
然而,C的这种直观简洁的模型过于底层和琐碎,不利于应用在那些构造复杂、变化多样的应用中。针对C的这些弱点,Bjarne Stroustrup决心利用OOP技术对C语言进行改造,从而促使了C++的诞生。C++全面(几乎100%)地兼容C,试图以此在不损失C语言的直观 和简洁的情况下,同时具备更强的软件工程特性,使其具备开发大型复杂系统的优势。这个目标“几乎”达到了,但是代价颇为可观。
在经历了80、90年代的辉煌之后,C++的应用领域开始退步。一方面,在底层应用方面,C++的很多特性被认为是多余的。如果不使用这些特性,那么 C++则同C没有什么差别。相反这些特性的使用,对开发团队的整体能力提出了更高的要求。因而,在最底层,很多人放弃了C++而回归了C,因为那些高级特 性并未带来很多帮助,反而产生了很多负担。另一方面,在高层开发中,业务逻辑和界面也无需那么多底层的特性和苛刻的性能要求,更多简单方便、上手容易的语 言相比C++更加适合。C++的应用被压缩在中间层,随着业界系统级开发的不断专业化,C++的使用规模也会越来越小。(当然,它所开发的应用往往都是关 键性的,并且是没有选择余地的)。实际上,C++在这个层面也并非完美的工具。目前无法取代是因为没有相同级别的替代品。D或许是个强有力的竞争者,但一 方面出于历史遗留代码的规模和应用惯性,另一方面D也并未完全解决C++面临的复杂性问题,D也很难在可见的将来取代C++。
实际上,C++的这种尴尬地位有着更深层次的原因。C++的本意是在保留C的底层特性基础上,增加更好的软件工程特性。但是,C++事实上并未真正意义上 地保留C的底层特性。回顾一下C的设计理念——直观而简洁地反映底层硬件的特性。C++通过兼容C获得了这种能力。但是这里有个问题,如果我要获得C的这 种简单直观性,就必须放弃C++中的很多高级特性。这里最明显的一个例子便是pod(plain old data)。
在C中压根没有pod的概念,因为所有的对象都是pod。但是,C++中有了pod。因为C++的对象可能不是一个pod,那么我们便无法象在C当中那样 获得直观简洁的内存模型。对于pod,我们可以通过对象的基地址和数据成员的偏移量获得数据成员的地址,或者反过来。但在非pod对象中,却无法这么做。 因为C++的标准并未对非pod对象的内存布局作出定义,因而对于不同的编译器,对象布局是不同的。而在C中,仅仅会因为底层硬件系统的差异而影响对象布 局。
这个问题通常并不显而易见。但在很多情况下为我们制造了不小的障碍。比如,对象的序列化:我们试图将一个对象以二进制流的形式保存在磁盘中、数据库中,或 者在网上传输,如果是pod,则直接将对象从基地址开始,按对象的大小复制出来,或传输,或存储,非常方便。但如果是非pod,由于对象的不同部分可能存 在于不同的地方,因而无法直接复制,只能通过手工加入序列化操作代码,侵入式地读取对象数据。(这个问题不仅仅存在于C++,其他语言,如java、C# 等都存在。只是它们没有很强烈的性能要求,可以使用诸如reflect等手段加以处理)。同样的问题也存在于诸如hash值的计算等方面。这对很多开发工 作造成不小的影响,不仅仅在底层,也包括很多高层的应用。
究其原因,C++仅仅试图通过机械地将C的底层特性和OOP等高层特性混合在一起,意图达到两方兼顾的目的。但是,事与愿违,OOP的 引入实际上使得C的编程模型和其他更高级的抽象模型无法兼容。在使用C++的过程中,要么只使用C的特性,而无法获得代码抽象和安全性方面的好处,要么放 弃C的直观简洁,而获得高层次的抽象能力。反而,由于C和OOP编程模型之间的矛盾,大大增加了语言的复杂性和缺陷数。

舍弃

但是,我们可以看到在C++中,并非所有的高级特性都与C的底层特性相冲突。很多使用C而不喜欢C++的人都表示过他们原意接受OB,也就是仅仅使用封装 。对于RAII,基本上也持肯定的态度。或许也会接受继承,但也表露出对这种技术带来的复杂性的担心。动多态是明显受到排斥的技术。显然这是因为动多态破坏了C的编程模型,使得很多本来简单的问题复杂化。不是它不好,或者没用,是它打破了太多的东西。
因而,我们设想一下,如果我们去除动多态特性,那么是否会消除这类问题呢?我们一步步看。
动多态的一个基本支撑技术是虚函数。在使用虚函数的情况下,类的每一次继承都会产生一个虚函数表(vtable),其中存放的是指向虚函数的指针。这些虚函数表必须存放在对象体中,也就是和对象的数据存放在一起(至少要关联在一起)。因而,对象在内存里并不是以连续的方式存放,而被分割成不同的部分,甚至身首异处(详见《Inside C++ Object Model》)。这便造成了前面所说的非pod麻烦。一旦放弃虚函数和vtable,对象的内存布局中,便不会有东西将对象分割开。所有的对象的数据存储都是连续的,因而都是pod。在这一点上,通过去除vtable,使得语言回归了C的直观和简单。
动多态的内容当然不仅仅是一个虚函数,另一个重要的基石是继承。当然,我们并不打算放弃继承,因为它并不直接破坏C的直观性和简洁性。不同于虚函数,继承 不是完全为了动多态而生的。继承最初的用途在于代码复用。当它被赋予了多态含义后,才会成为动多态的基础。以下的代码可以有两种不同的解读:
class B : public A {};
代码复用的角度来看,B继承自A,表示我打算让B复用A的所有代码,并且增加其他功能。而从多态的角度来看,B是一个A的扩展,B和A之间存在is-a的 关系。(B是一个A)。两者是站在不同层面看待同一个问题。代码复用,代表了编码的观点,而多态,则代表了业务逻辑的观点。但是,两者并非实质上的一回 事。在很多情况下,基类往往作为继承类的某种代表,或者接口,这在编码角度来看并没有对等的理解。而这种接口作用,则是动多态的基础。动多态通过不同的类 继承自同一个基类,使它们拥有共同的接口,从而可以使用统一的形式加以操作。作为一个极端,interface(或者说抽象基类),仅仅拥有接口函数(即vtable)而不包含任何数据成员。这是纯粹的接口。
然而,这里存在一个缺陷。一个接口所代表的是一组类,它将成为这一组类同外界交互的共同界面。但是,使用基类、或者抽象基类作为接口,实质上是在使用一个 类型来代表一组类型。打个比方,一群人凑在一起出去旅游,我们称他们这群人为“旅行团”。我们知道旅行团不是一个人,而是一个不同于“人”的概念。动多态 里的接口相当于把一个旅行团当作一个人来看待。尽管这只是逻辑上的,或许一个旅行团的很多行为和一个人颇为相似。但是根本上而言,两者毕竟不是相同层次的 概念。这样的处理方法往往会带来了很多弊端。
为了使继承被赋予的这重作用发挥作用,还需要一项非常关键的处理:类型转换。请看以下代码:
void func(A* a);
B b;
func(&b);
最后这行代码施行了动多态,如果B override了A的虚函数的话。很显然,如果严格地从强类型角度而言,&b是不应当作为func的实参,因为两者类型不匹配。但是如果拒绝接 受&b作为实参,那么动多态将无法进行下去。因此,我们放宽了类型转换的限制:允许继承类对象的引用或指针隐式地转换成基类的引用或指针。这样, 形如func(&b);便可以顺理成章地成为合法的代码。
然而,这也是有代价的:
B ba[5];
func(ba);
后面这行函数调用实际上是一个极其危险的错误。假设在func()中,将形参a作为一个类型A的数组对待,那么当我们使用ba作为实参调用func()的 时候,会将ba作为A的 数组处理。我们知道,数组内部元素是紧挨着的,第二个元素的位置是第一个元素的基址加上元素的尺寸,以此类推。如果传递进来的对象数组是B类型的,而被作 为A类型处理,那么两者的元素位置将可能不同步。尽管B继承自A,但是B的尺寸很有可能大于A,那么从第二个元素起,a[1]的地址并非ba[1]的地 址。于是,当我们以a[1]访问ba时,实际上很可能在ba[0]的内部某个位置读取,而func()的代码还以为是在操作ba[1]。这便是C++中的 一个重要的陷阱——对象切割。这种错误相当隐蔽,危险性极大。
由于C++试图保留C的编程模型,因而保留了指针-数组的等价性。这种等价性体现了数组的本质。这在C中是一项利器,并无任何问题。但在C++中,由于存 在了继承,以及继承类的隐式类型转换,使得这种原本滋补的特性成为了一剂毒药。换句话说,C++所引入的动多态破坏了C的直观性。

舍弃之后

从上面的分析来看,动多态同C的编程模型是不相容的。因而如果希望得到C的直观性,并且消除C++的缺陷,必须放弃动多态这个特性。现在来看看放弃之后将会怎样。
一旦放弃了动多态,也就放弃了虚函数和vtable。此时,所有的对象都是pod了。那么首当其冲的好处,就是可以进行非侵入的序列化、hash计算等等 操作。由于对象肯定是连续分布的,可以直接地将对象取出进行编码、存储、计算和传输,而无需了解对象内部的数据结构和含义。另外一个重要的问题也会得到解 决,这就是ABI。在C中统一的ABI很自然地存在于语言中。我们可以很容易地用link将两个不同编译器编译的模块连接起来,而不会发生问题。但 是,C++中做不到,除非不再使用类而使用纯C。目前C++还没有统一的ABI,即便标准委员会有意建立这样的规范,实现起来也绝非易事。但是,如果放弃 动多态之后,对象的布局便回归到C的形态,从而使得ABI不再成为一个问题。
另一方面,随着动多态的取消,那么继承的作用被仅仅局限于代码复用,不再具有构造接口的作用。我们前面已经看到,继承类向基类的隐式转换,是为了使基类能 够顺利地成为继承类的接口。既然放弃了动多态,那么也就无需基类再承担接口的任务。那么由继承类向基类的隐式类型转换也可以被禁止:
void func(A* a);
B b;
func(&b); //编译错误,类型不匹配
进而对象切割也不会发生:
B ba[5];
func(ba); //编译错误,类型不匹配
尽管根据数组-指针的等价性,ba可以被隐式地转换为B*,但是B*不再能够隐式地转换为A*,从而避免了对象的切割。
问题是,如此简单地将动多态放弃掉,就如同将水和孩子一起泼掉那样,实际上放弃了动多态带来的好处。实际上并非如此。我们放弃动多态这个特性,但并不打算放弃它所具有的功能,而是用另一种技术加以替代。这便是runtime concept(这里这里)。
不同于以类型为基础的interface,concept是独立于类型的系统。concept生来便是为了描述一组类型,因而是接口最理想的实现手段。当concept runtime化之后,便具有了与动多态相同的功能(很多方面还有所超越)。
runtime concept同样需要类似vtable的函数分派表,但由于它不是类型,这些分派表无需存放在对象内部,可以独立放置(可以同RTTI信息放在一起), 并且只需一份。正是基于这个特性,方才保证了所有对象依然是pod,依然能够保证对象布局的直观性。
同样,runtime concept承担了接口的任务,但不象动多态那样依赖于继承和相应的隐式类型转换。(通过自动或手动的concept_map)。因而,我们依旧可以禁止基于继承关系的隐式类型转换,从而防止对象切割的情况。
一旦使用concept作为多态的实现手段,反倒促使原本动多态的一些麻烦得到消除。在动多态中,必须指定virtual函数。如此,在一个类中会存在两 种不同形态的函数,实现动多态的虚函数,和无此功能的普通函数。准确地维护这样两种函数,颇有些难度。而且,函数是虚还是不虚,牵涉到系统的设计,必须在 最初构建时确定,否则以后很难修改。但在放弃动多态,使用concept的情况下,只要一个继承类中,使用相同的签名覆盖基类中的函数,便实现了多态。当 进行concept_map,即将接口与类绑定时,只会考虑继承类的函数,而忽略基类中被覆盖的函数。于是,只需简单的覆盖,便实现了多态的控制。对于是 否多态一个函数,即是否改变基类函数的行为,完全由继承类控制,在创建基类时不必为此伤神。其结果就是,我们无需在系统设计的最初一刻就操心多态的问题, 而只需根据实现的需要随时实现。

其他

存在大量隐式转换也是C++常受人诟病的一个方面,(特别是那些Pascal系的程序员)。隐式转换的目的是带来方便,使得编码更加简洁,减少冗余。同时也使得一些技巧得以施行。但是,隐式转换的副作用也颇为可观。比如:
void fun(short a);
long a=1248;
fun(a); //顶多一个警告
这种转换存在两面性:一方面,它可能是合理的,因为尽管a类型long大于short,但很可能存放着short可容纳的数值;但另一方面,a的确存在short无法容纳的可能性,这便会造成一个非常隐蔽的bug。
C/C++对此的策略是把问题扔给程序员处理,如果有bug那是程序员的问题。这也算得上合情合理,毕竟有所得必有所失,也符合C/C++的一贯理念。但 终究不是最理想的方式。但是如果象Pascal那样将类型管得很死,那么语言又会失去灵活性,使得开发的复杂性增加。
如果试图禁止隐式类型转换,那么为了维持函数使用代码的简洁性,函数必须对所有的类型执行重载。这大大增加了函数实现的负担,并且重复的代码严重违背了DRY原则。
现在或许存在一些途径,使得在维持绝对强类型的情况下获得所希望的灵活性。钥匙可能依然在concept手上。考虑如下的代码:
void fun(Integers a);
long a=1248;
fun(a);
longlong b=7243218743012;
fun(b);
此处,fun()是一个函数,它的形参是一个concept,代表了所有的整型。这样,这个函数便可以接受任何一种整型(或者具有整型行为的类型)。我们 相信,在一般的应用下,任何整数都有完全相同的行为。因此,我们便可以很方便地使用Integers这个接口执行对整数的操作,而无需关心到底是什么样的 整数。
如此,我们便可以在禁止隐式类型转换,不使用函数重载的情况下,完成这种函数的编写。同时可以得到更好的类型安全性。

强制类型转换是非常重要的特性,特别是在底层开发时。但也是双刃剑,往往引来很隐蔽的错误。强制类型转换很多情况下是无理的,通常都是软件的设计问题造成的。但终究还是有一些情况,需要它来处理。
设想这样一个场景:两个一模一样的类型,但它们分属不同的函数。(这种情形尽管不多见,但还是存在的。这往往是混乱设计的结果。当然也有合理的情况,比如 来自两个不同库的类型)。我现在需要写一个函数,能够同时使用这两个类型。比较安全一些的,可以用函数重载。但是两个重载的函数代码是一样的,典型的冗余 代码。当然也可以针对其中一个结构编写代码,然后在使用时,对另一个结构的实例执行强制类型转换。但是,强制类型转换毕竟不是件好事。因此,我们也可以构 造一个concept,让它描述这两个类型。然后在编写函数时使用这个concept,当这两个类型都与concept绑定后,便可以直接使用这两个类 型,而没有类型安全和代码冗余的问题。
(顺便提一下,这种方式也可以运用在类型不同的情况下。比如两个类型不完全相同,但是基本要素都一样。那么就可以使用concept_map的适配功能,将两个类型统一在一个concept下。这种方式相比oop的Adapter模式,更加简洁。adapter本身是一个container,它所实现的接口函数,都必须一一转发到内部的对象,编写起来相当繁琐。但在concept_map中,对于那些符合concept描述的函数无需另行处理,concept会自动匹配,只需对那些不符合要求的函数执行适配。)

前面说过,指针数组的等价性体现了一种直观的编程模型。但是,指针和数组毕竟还是存在很多差别,比如指针仅仅表达了一组对象在内存中的位置,但并未携带对象数量的信息。因而,当数组退化成指针时,便已经失去了数组的身份:
void func(int* x);
int a[20];
func(a);
这里,在函数func中已经无法将a作为数组处理,因为无法知道变成int*后的a有多大来避免越界。甚至我们无法把a作为多个对象构成的内存块看待,因为我们不知道大小。因此,只有显式地给出数组大小,才能使用:
void func(int* x, long size);
但是,在concept的作用下,数组和指针得以依然保持它们的等价性的情况下,解决数组退化问题。考虑这样两个函数:
void func1(Pointer x);
void func2(Container x);
其中,Pointer是代表指针的concept,而Container则是代表容器的concept。必须注意的是,Pointer是严格意义上的指 针,也就是说无法在Pointer上执行迭代操作。Pointer只能作为指针使用,只具备dereference的能力(很像java的“指针”,不是 吗?concept在没有放弃C的底层特性的情况下也做到了。)。而Container则是专门用来表达容器的concept,其基本的特性便是迭代。在 func1中,无法对形参x执行迭代,仅仅将其作为指向一个对象的指针处理,保证其安全性。而对于需要进行迭代操作的func2而言,x则是可以遍历的。 于是,对于同一个数组a,两个函数分别从不同的角度对其进行处理:
int a[20];
func1(a); //a直接作为指针处理,但不能迭代
func2(a); //a作为容器处理,可以迭代,并且其尺寸信息也一同传入
此处实际上是利用了concept对类型特性的描述作用,将具有两重性的数组类型(数组a即代表了数组这个容器,也代表了数组的起始地址)以不同特征加以 表达,以满足不同应用的需求。数组仍然可以退化成指针,C的直观模型得到保留,在很多特殊的场合发挥作用。但在其他应用场景,可以更加安全地使用数组。

总结

综上所述,C++未能真正延续C的直观简洁,主要是由于动多态的一些基础设施破坏了C的编程模型。因而,我们可以通过放弃动多态,及其相关的一些技术,代 之以更加“和谐”的runtime concept,使得C++在基本保留C的编程模型的同时,获得了相比原来更好的软件工程特性。至此,这种改变后的C++(如果还能称为C++的话)拥有 如下的主干特性:
1、SP,来自于C。
2、完全pod化。
3、OB。保留了封装和RAII。尽管也保留了继承,但其作用仅限于代码复用,禁止基于继承的隐式类型转换。
4、GP,包括static和runtime concept。这是抽象高级特性的核心和基石。
这样的语言特性实质上比现有的C++更加简洁,但是其能力更加强大。也比C++更易于贴近C的编程模型,以便适应底层的开发。我不能说这样的变化是否会产生一个更好的语言,但是我相信这些特性有助于构造更加均衡统一的语言。
分享到:
评论

相关推荐

    ArcGIS Python开发

    - 示例:`D = {"ProductName": "desktop", "InstallDir": "c:\\ArcGIS\\Desktop10.0"}` - **Python中的控制流语句**: - **条件语句(if/else)**:根据条件执行不同的代码块。 - 示例:检查变量是否为特定值,...

    spring-ai-oracle-store-1.0.0-M7.jar中文文档.zip

    # 【spring-ai-oracle-store-1.0.0-M7.jar中文文档.zip】 中包含: 中文文档:【spring-ai-oracle-store-1.0.0-M7-javadoc-API文档-中文(简体)版.zip】 jar包下载地址:【spring-ai-oracle-store-1.0.0-M7.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【spring-ai-oracle-store-1.0.0-M7.jar Maven依赖信息(可用于项目pom.xml).txt】 Gradle依赖:【spring-ai-oracle-store-1.0.0-M7.jar Gradle依赖信息(可用于项目build.gradle).txt】 源代码下载地址:【spring-ai-oracle-store-1.0.0-M7-sources.jar下载地址(官方地址+国内镜像地址).txt】 # 本文件关键字: spring-ai-oracle-store-1.0.0-M7.jar中文文档.zip,java,spring-ai-oracle-store-1.0.0-M7.jar,org.springframework.ai,spring-ai-oracle-store,1.0.0-M7,org.springframework.ai.vectorstore.oracle,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,springframework,spring,ai,oracle,store,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压 【spring-ai-oracle-store-1.0.0-M7.jar中文文档.zip】,再解压其中的 【spring-ai-ora

    3dmax插件丢失贴图.ms

    3dmax插件

    azure-ai-openai-1.0.0-beta.3.jar中文文档.zip

    # 压缩文件中包含: 中文文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

    (专升本)C语言历年考试题及答案2.doc

    (专升本)C语言历年考试题及答案2.doc

    spring-ai-mongodb-atlas-store-1.0.0-M5.jar中文文档.zip

    # 压缩文件中包含: 中文文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

    基于Matlab/Simulink的DSTATCOM无功补偿风电并网模型仿真与优化

    内容概要:本文介绍了利用Matlab/Simulink搭建的带有DSTATCOM无功补偿的风电并网模型及其仿真结果。模型中包含了双馈风机(DFIG)和鼠笼感应风机(SCIG),并通过DSTATCOM实现了对电压波动的有效抑制。文中详细描述了DSTATCOM的控制策略,包括电压-无功闭环控制、PI控制器的设计以及低电压穿越功能的实现。此外,还讨论了仿真过程中遇到的一些常见问题及解决方案,如参数选择不当引起的过冲现象、仿真加速技巧等。 适合人群:从事电力系统、风电并网研究的技术人员和研究人员。 使用场景及目标:适用于希望深入了解风电并网系统中无功补偿机制的研究人员和技术人员,旨在提高对DSTATCOM控制策略的理解,掌握解决电压不稳定问题的方法。 其他说明:文中提供了详细的控制算法代码片段,有助于读者更好地理解和复现实验结果。同时,作者分享了一些实用的经验和技巧,如参数调整、仿真加速方法等,对于实际应用具有重要参考价值。

    【基于矢量射线的衍射积分 (VRBDI)】基于矢量射线的衍射积分 (VRBDI) 和仿真工具附Matlab代码.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

    langchain4j-ollama-0.26.1.jar中文文档.zip

    # 压缩文件中包含: 中文文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

    ### 中国智能制造产业发展报告(2023-2024年)总结、智能制造概述

    内容概要:本文详细介绍了2023-2024年度中国智能制造产业发展情况。报告由多个部门和机构联合编写,涵盖智能制造总述、AI赋能制造业转型升级、全球智能制造发展形势、中国智能制造概况、产业分析、发展规划及优秀案例。报告指出,智能制造已成为提升制造业竞争力的国家战略,强调了新一代信息技术与制造业深度融合的重要性。文中分析了中国智能制造的优势、面临的挑战及未来的发展目标,强调了政策引领、试点先行和跨域协同的重要性。同时,报告探讨了AI在智能制造中的应用,特别是大模型对制造业的推动作用,并列举了多个行业和地区的智能制造政策和具体案例,展示了智能制造在中国的广泛应用和未来发展潜力。 适用人群:政府相关部门、智能制造领域的研究人员、企业高管和技术人员、高等院校相关专业的师生等。 使用场景及目标:①帮助政府和企业了解智能制造的最新发展动态和政策导向;②为制造业企业提供智能化转型的参考案例和技术解决方案;③为高校和研究机构提供智能制造领域的研究素材和方向;④促进智能制造技术的普及和应用,推动制造业高质量发展。 阅读建议:此报告内容详尽,涵盖了智能制造的多个方面,读者应重点关注中国智能制造的优势、面临的挑战、发展目标及相关政策。同时,结合实际工作或研究需求,深入研读具体章节和案例,以获得更有针对性的知识和启示。

    自动驾驶车辆运动控制中PID参数优化的强化学习探索:基于DDPG算法的解决方案

    内容概要:本文探讨了在自动驾驶车辆运动控制中,传统PID控制算法由于参数固定的局限性,难以适应复杂的路况和车速变化的问题。为了克服这一挑战,文章介绍了如何利用基于Actor-Critic框架的DDPG(深度确定性策略梯度)算法来动态调整PID控制参数。具体来说,Actor网络负责输出优化后的PID参数,而Critic网络则评估这些参数的效果。通过不断的学习和调整,使车辆能够在各种情况下表现出更好的控制性能。此外,文中还详细描述了奖励函数的设计,确保控制不仅精确而且平稳。 适合人群:从事自动驾驶研究的技术人员、对强化学习应用于实际控制系统感兴趣的学者及工程师。 使用场景及目标:适用于希望提升自动驾驶车辆在复杂道路条件下的稳定性和灵活性的研究项目。目标是在不同路况和车速条件下,通过动态调整PID参数,提高车辆的控制精度和平顺性。 其他说明:文章提供了具体的代码示例,帮助读者理解和实现相关算法。同时也指出了在实际应用中可能遇到的问题及其解决办法,如参数调整的边界约束、状态输入的数据平滑处理等。

    spring-ai-opensearch-store-1.0.0-M5.jar中文文档.zip

    # 压缩文件中包含: 中文文档 jar包下载地址 Maven依赖 Gradle依赖 源代码下载地址 # 本文件关键字: jar中文文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

    spring-ai-model-chat-memory-jdbc-1.0.0-M7.jar中文-英文对照文档.zip

    # 【spring-ai-model-chat-memory-jdbc-1.0.0-M7.jar中文-英文对照文档.zip】 中包含: 中文-英文对照文档:【spring-ai-model-chat-memory-jdbc-1.0.0-M7-javadoc-API文档-中文(简体)-英语-对照版.zip】 jar包下载地址:【spring-ai-model-chat-memory-jdbc-1.0.0-M7.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【spring-ai-model-chat-memory-jdbc-1.0.0-M7.jar Maven依赖信息(可用于项目pom.xml).txt】 Gradle依赖:【spring-ai-model-chat-memory-jdbc-1.0.0-M7.jar Gradle依赖信息(可用于项目build.gradle).txt】 源代码下载地址:【spring-ai-model-chat-memory-jdbc-1.0.0-M7-sources.jar下载地址(官方地址+国内镜像地址).txt】 # 本文件关键字: spring-ai-model-chat-memory-jdbc-1.0.0-M7.jar中文-英文对照文档.zip,java,spring-ai-model-chat-memory-jdbc-1.0.0-M7.jar,org.springframework.ai,spring-ai-model-chat-memory-jdbc,1.0.0-M7,org.springframework.ai.chat.memory.jdbc,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,springframework,spring,ai,model,chat

    tokenizers-0.25.0.jar中文文档.zip

    # 【tokenizers-***.jar***文档.zip】 中包含: ***文档:【tokenizers-***-javadoc-API文档-中文(简体)版.zip】 jar包下载地址:【tokenizers-***.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【tokenizers-***.jar Maven依赖信息(可用于项目pom.xml).txt】 Gradle依赖:【tokenizers-***.jar Gradle依赖信息(可用于项目build.gradle).txt】 源代码下载地址:【tokenizers-***-sources.jar下载地址(官方地址+国内镜像地址).txt】 # 本文件关键字: tokenizers-***.jar***文档.zip,java,tokenizers-***.jar,ai.djl.huggingface,tokenizers,***,ai.djl.engine.rust,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,djl,huggingface,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压 【tokenizers-***.jar***文档.zip】,再解压其中的 【tokenizers-***-javadoc-API文档-中文(简体)版.zip】,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件; # Maven依赖: ``` <dependency> <groupId>ai.djl.huggingface</groupId> <artifactId>tokenizers</artifactId> <version>***</version> </dependency> ``` # Gradle依赖: ``` Gradle: implementation group: 'ai.djl.huggingface', name: 'tokenizers', version: '***' Gradle (Short): implementation 'ai.djl.huggingface:tokenizers:***' Gradle (Kotlin): implementation("ai.djl.huggingface:tokenizers:***") ``` # 含有的 Java package(包): ``` ai.djl.engine.rust ai.djl.engine.rust.zoo ai.djl.huggingface.tokenizers ai.djl.huggingface.tokenizers.jni ai.djl.huggingface.translator ai.djl.huggingface.zoo ``` # 含有的 Java class(类): ``` ai.djl.engine.rust.RsEngine ai.djl.engine.rust.RsEngineProvider ai.djl.engine.rust.RsModel ai.djl.engine.rust.RsNDArray ai.djl.engine.rust.RsNDArrayEx ai.djl.engine.rust.RsNDArrayIndexer ai.djl.engine.rust.RsNDManager ai.djl.engine.rust.RsSymbolBlock ai.djl.engine.rust.RustLibrary ai.djl.engine.rust.zoo.RsModelZoo ai.djl.engine.rust.zoo.RsZooProvider ai.djl.huggingface.tokenizers.Encoding ai.djl.huggingface.tokenizers.HuggingFaceTokenizer ai.djl.huggingface.tokenizers.HuggingFaceTokenizer.Builder ai.djl.hu

    【企业智能化转型】腾讯云DeepSeek大模型知识引擎:提升企业人效与业务增长的智能解决方案

    内容概要:本文介绍了腾讯云DeepSeek大模型知识引擎在企业服务中的应用,旨在提升企业人效和业务增长。大模型具备理解、学习、生成和推理能力,已在智能客服、智能办公等领域落地。文章详细介绍了三种主要应用模式——标准模式、工作流模式和Agent模式,分别适用于不同需求场景。此外,还展示了知识引擎在企业行政问答、专业知识查询、质检、保险建议书生成等具体业务中的成功案例。针对大模型应用中的难点,如企业知识更新快、知识格式多样等问题,腾讯云提供了全链路解决方案,涵盖知识获取、处理、检索、理解和生成。最后,文章强调了大模型知识引擎的安全防护措施,确保数据资产的安全。 适合人群:企业管理人员、信息技术部门负责人、数据科学家、AI开发者等关注企业智能化转型的专业人士。 使用场景及目标:①通过智能客服、智能办公等场景提高员工工作效率;②利用标准模式、工作流模式和Agent模式满足不同业务需求;③解决企业知识更新快、知识格式多样等实际难题,提升业务处理的准确性和效率;④保障企业数据安全,防止敏感信息泄露。 其他说明:本文还探讨了大模型在金融舆情摘要、投顾服务、投研服务、车险评残业务等领域的潜在应用场景,展示了大模型知识引擎的广泛适用性和强大功能。

    电源.SCHLIB

    电源.SCHLIB

    基于小脑模型神经网络的轨迹跟踪研究附Matlab代码.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

    西门子PLC1500与Fanuc机器人在汽车焊装产线的应用及优化

    内容概要:本文详细介绍了西门子PLC1500与Fanuc机器人在汽车焊装生产线中的应用及其优化措施。首先,文章描述了PLC1500的核心架构,包括9个ET200SP远程站、16个Festo气动模块以及Profinet拓扑结构。接着,探讨了机器人通讯方式,如使用TSEND_C/TRCV_C指令进行数据交换,并展示了具体的焊接参数下发实例。此外,还讨论了SCL算法在电流平衡逻辑中的应用,以及GRAPH顺控程序在车门焊接流程中的高效实现方法。文中还提到了安全模块配置、诊断功能堆栈设计、MES系统交互等方面的技术细节。最后,强调了混合编程的优势,特别是在处理复杂数据交互时的表现。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是熟悉PLC编程和机器人控制的专业人士。 使用场景及目标:适用于需要深入了解PLC1500与Fanuc机器人协同工作的技术人员,帮助他们掌握先进的编程技巧和优化方法,提高生产效率和安全性。 其他说明:本文不仅提供了详细的代码示例,还分享了许多实际项目中的经验和教训,有助于读者更好地理解和应用相关技术。

    MATLAB实现虚拟电厂中电转气协同与碳捕集优化调度的研究

    内容概要:本文详细介绍了如何使用MATLAB实现虚拟电厂中电转气(P2G)协同与碳捕集的优化调度。虚拟电厂将垃圾焚烧发电、碳捕集装置和电转气设备整合在一起,通过构建包含28个决策变量的优化模型,最小化总运行成本。模型的目标函数涵盖了燃料成本、碳交易成本、P2G运行成本等多个方面。文中展示了具体的MATLAB代码实现,包括目标函数、约束条件、求解器配置等方面的内容。此外,还讨论了电转气设备的建模、需求响应模块的设计以及碳捕集装置的能耗管理等问题。实验结果显示,引入P2G后总成本降低了12.7%,碳排放强度下降了21.3%。 适合人群:从事能源系统优化、虚拟电厂调度、碳捕集技术和电转气技术研究的专业人士和技术爱好者。 使用场景及目标:适用于希望深入了解虚拟电厂中多能耦合调度策略及其MATLAB实现的研究人员和工程师。主要目标是掌握如何通过优化模型降低运行成本和碳排放强度。 其他说明:文章强调了在实际应用中需要注意的一些细节,如CPLEX求解器的内存瓶颈、碳捕集装置的能耗管理、电转气设备的启停成本等。

    基于DSP6713的以太网激光打标卡源码解析:工业级应用中的高效稳定实现

    内容概要:本文深入探讨了基于DSP6713的以太网激光打标卡的源码实现及其在工业自动化领域的应用。文章详细介绍了DSP6713的特点,如高性能浮点运算能力和丰富的外设接口,使其适用于复杂激光打标算法的快速处理。重点解析了以太网通信模块和激光控制部分的源码,展示了如何通过合理的模块设计和代码实现,确保高速、稳定的数据传输与精准的激光控制。此外,文中还讨论了一些关键技术和优化技巧,如双缓冲DMA、自定义协议栈、PID+前馈补偿算法、任务调度、异常恢复系统等,强调了这些技术在提升系统性能和稳定性方面的重要作用。 适用人群:从事嵌入式系统开发、工业自动化、激光打标技术研究的专业人士和技术爱好者。 使用场景及目标:①帮助读者理解DSP6713在以太网激光打标卡中的具体应用;②提供详细的源码解析,便于开发者进行二次开发和优化;③分享工业级应用中的实践经验,提升系统的性能和稳定性。 其他说明:文章不仅关注代码的具体实现,还涵盖了大量实用的技术细节和优化方法,有助于读者全面掌握该领域的核心技术。

Global site tag (gtag.js) - Google Analytics