语义的需要

语义SLAM综述 语义SLAM综述 摘要 SLAM技术在计算机视觉和机器人领域中占有重要地位。传统的SLAM框架采用了较强的静态世界假设,便于分析。大多基于小区域静态环境。在大规模的动态环境下,它们大多难以获得较好的性能,系统的准确性、快速性仍需加强。如何应对动态环境是一个非常重要而又备受关注的问题。现有的面向动态场景的SLAM系统要么只利用语义信息,要么只利用几何信息,要么以松散耦合的方式天真地组合它们的结果。近... 阅读详情

    见过不少拙劣的设计,不少程序员都只为最终功能的实现,完全不管语义的需要,编写出低劣的代码,几乎没有语义这个概念,而我认为这是一个程序员的修养问题,对于一个程序员其具有深远的意义。
    语义就是语言的意义,在电脑编程方面来说就是对内存操作及机器指令执行的解释。它表现出程序编写人逻辑思维的清晰与否,不仅仅应用在电脑编程方面,还可往社会上推,也就是所谓的权责明确。就系统设计员的角度来说,语义表示各个接口的意义,它指导设计者如何设计接口函数的参数类型及接口函数的名字(即意义),就一个管理层人士其表示下面的各功能部门存在的必要性,各功能机构的职责及其业务流程如何制订。不过本文仅讨论语义在电脑编程方面中最底层的写代码这个环节中的意义,其是不容忽视的。具有良好语义的代码调试容易,稳定性高,可读性好。在此仅讨论C++语言所提供的语义及使用。


类型

    C++提供了char、int、long等多种基础变量类型,这些类型就已经提供了语义——unsigned long表示这个变量里面放的数字被认为是一个而非是一个无符号长整型数字。“认为是”和“是”是有严重区别的。任何类型的变量都“是”数字,而变量的类型除了说明其所占内存空间的大小外,还被附带了语义,表示其应该被代码阅读者和代码编写人共同“认为是”某种意义,而非一个数字。这就正如我们会说一个字节数组是一个位图而不是一个数组。
    类型的运用在各个库中均有大量运用。Win32 API中,HWND、HANDLE等句柄其实都只是一个void*;LPARAM、WPARAM等也都只是一个四字节数字而已。但它们都被赋予了重要的意义,HWND表示一个窗口句柄而不是一个指针,表示程序员不应该将其视为一个指针,而应该是一个cookie,一个序号,通过将其传递给Win32 API来操作对应的窗口(即使它其实就是个指针)。当然,Win32 API中也还是有很多仅仅为了方便而作的类型定义,如:UINT、USHORT等。
    编写代码时,应该选取正确的变量类型。如进行一个for( unsigned long i = 0; i < count; ++i)循环枚举一个数组的各元素进行操作,i就应该使用unsigned的类型,而count也应该使用unsigned类型。因为是枚举一个数组,i代表数组下标,在C++中数组的下标是≥0的,因此应该使用unsigned,而count代表数组个数,个数逻辑上最小只能为零,故也应该使用unsigned。这个例子看起来有点极端,但它表现出程序员清晰的逻辑,如果count和i分别是由两个程序员定义的(这更极端了),那么那两个程序员如果都按照语义编写将会得到配合默契的代码(都使用unsigned,在for循环的比较中就不需要类型转换了),而这正是修饰成员函数的const的主要应用。
    除了变量类型,变量名字也是语义的体现,为此而出现如匈牙利命名规则等多种变量命名规则。最好能养成自己的变量命名规则并严格按其命名变量,将会使代码的可读性上一个台阶。对于函数的命名也是同样的。


修饰变量的const

    const关键字用于表示其所修饰的变量的值是不能修改的。应该注意,不是“不能修改”,而是“不是用来写入的”,而“不能修改”是其附加效果(或实现方式),结果const修饰的变量就被称为常数,这正是“不是用来写入的”的体现。C语言中使用宏来定义常数的坏处就是宏无法让编译器加入语义检查的行列,因为没有类型信息。使用const变量就将类型信息告诉了编译器,编译器可以进行少许的语义检查——类型匹配检查,因此定义常数时应一律使用const变量,而宏应该用于代码的配置(如定义代码版本,像Unicode版本)和代码编写的简化(视为inline函数)。


修饰成员函数的const

    const修饰成员函数时,表示所修饰的成员函数不能修改其对应类的成员变量的值。同样,不是“不能修改”,而是“不会修改”,“不能修改”是其附加效果(或实现方式)而已。见过一些老师讲课及某些教材上将const成员函数说成是帮助程序员发现逻辑错误用的,即恐怕程序员自己在不能修改成员变量的函数中修改了成员变量而要编译器协助检查!这是真正的本末倒置!如果一个程序员在const成员函数中修改了成员变量,那只能说明那个程序员的逻辑混乱,自己都不清楚在编些什么,根本还不够程序员的资格。他们一般发现警告了,就将那个const去掉,更有甚者则是从不使用const这个关键字修饰成员函数。
    const是在写代码前就已经可以确定的,在编写类的定义时就可以确定这个成员函数是否应该是const的(通过这个成员函数的语义来确定)。最常见的就是一对Get/Set成员函数用以操作某个成员变量,如:
inline ULONG CAbcList::GetCount() const
{
    ASSERT_VALID( this );
    return m_Count;
}
BOOL CAbcList::SetCount( ULONG count )
{
    ASSERT_VALID( this );
    // 更多的代码
    m_Count = count;
    return TRUE;
}
    其中的Get成员函数在编写其定义前就可以确定其应该是const——取类实例(类的一个实例)的状态而已,逻辑上是不会影响类实例的状态的。但Set成员函数就一定不能是const的——设置类实例的状态,当然影响类实例的状态。再如在链表类中查找某个元素,逻辑上仍是与类实例无关,不会影响其状态,故仍旧应该是const的。确定const成员函数的工作严格来说应该是由设计者完成,与程序员无关(特指写代码的人),但一些简单的小类还是应该由程序员自己完成的,故仍应需要理解const的语义。
    使用const成员函数,如前面在类型中所提到的。有一个部门类,其有多个CAbcList的成员变量以分别存储人事、财务等信息,然后其有人事查找的成员函数,很明显地应该为const成员函数,在其中需要调用到CAbcList::GetCount。这里配合得非常恰当--在const成员函数中调用const成员函数,没有任何警告。如果这两个类分别由两个人编写,定义类时并不互相知道对方的定义,而大家都按照语义编写,则最后的代码就非常恰当地配合起来。
    但是仍可能出现在逻辑上应该是const的成员函数中需要修改成员变量的情况,对于此可参考下面的mutable中的例子。


类的public、protected、private

    类的public、protected以及private可以说只是为了语义而存在,对最终代码没有任何影响,但是它是如此的重要,因此导致面向对象的编程思想大行其道。已经见过不少说法——为了具有面向对象的思想,成员变量一律定为private的,全部通过上面提到的Get/Set成员函数(或类似函数)进行操作。下面解释这三个关键字的语义,不过应注意到前面那个说法的不正确性——至少MFC中的CWnd::m_hWnd就是public的。
    public  表示其所修饰的成员函数或成员变量可以被外界(类实例的操作者,即使用类实例的代码)看见。同样,不是“可以被看见”,而是“被用来看的”。比如开一个杂货店,门面本来就是拿来给行人看的,而不是门面可以被行人看见,这只是门面的附加效果(也可以说是实现方式),其目的是让行人看从而吸引行人进入杂货店买东西。
    所以一个成员函数是public的,表示它是专门用来被外界调用以操作类实例的,通常对这类成员函数有个很贴切的叫法——操作。如前面提到过的Get/Set成员函数就应该是public的。一个成员变量是public的,和成员函数一样,表示它是专门被外界操作的。如MFC中的CWnd::m_hWnd,其之所以是public的就是因为CWnd是一个包装类,其包装的就是对窗口句柄m_hWnd的操作,也就是说外界知道CWnd一定有个窗口句柄的成员变量,也就是m_hWnd。窗口句柄在这和类CWnd一起组成了一个逻辑——窗口句柄的包装类,故CWnd::m_hWnd是public的。而前面举的例子CAbcList::m_Count又为什么要使用Get/Set函数对来操作而不使用public成员变量?因为CAbcList是一个链表类,链表本身是没有元素个数这个概念的,只是可以得到其元素个数,而CAbcList使用了一个成员变量m_Count来记录元素个数是为了加快对元素个数的获得,即m_Count具有一些逻辑规则(保证其数值为链表个数),由CAbcList维护。所以m_Count应该是protected的,而不是public。
    总的来说,类所代表的意义所具有的属性就应该是public的,但如果属性是关联的,则应该使用成员函数将对属性的操作包装起来,以实现属性之间的联系。如:位图类的长宽,多边形立体模型的顶点数、多边形数就不应该是public的,因为它们都和各自的实现有关系——位图使用一个字节数组,多边形模型则使用顶点数组和多边形数组。改变长宽或顶点数就需要相应的修改字节数组或顶点数组。而智能指针由于是指针的包装,而且其包装的指针并没有和类的其他什么成员变量有联系,故其包装的指针成员变量应该为public。
    protected  表示其所修饰的成员函数或成员变量不能被外界看见,但可以被其派生类看见。同样,不是“可以被看见”,而是“被用来看的”。还是开杂货店,店里的帐本就不是拿给行人看,其对行人来说是保密的。不过后来杂货店要改建成小超市,帐本还是要被小超市使用的。在这里,帐本就是protected的成员。
    一个成员函数是protected的,表示它是专门用来被成员函数和派生类的成员函数调用,以帮助操作类实例的,通常这类成员函数就是就是辅助函数。比如链表类CAbcList为了能加快元素的查找,其有一个成员函数专门用于对元素进行排序,这个辅助函数被用于元素的排序插入操作和查找操作,并且其派生类也有可能调用它进行排序操作,故这个函数应该为protected的。
    一个成员变量是protected的,派生类的成员函数也可操作它,专用于可能会随派生类的不同而有不同用法。如果某个成员变量可以具有不同的操作方式,如前面的杂货店的帐本,在小超市时其可能由于支持批发业务而导致需要不同的记帐形式,即需要记录批发的相关信息,而原来的杂货店是不能记录批发相关的信息的。因此帐本这个杂货店类的成员变量应该是protected的。
    当不好确定成员变量是否将会具有不同的操作方式时,就将其定为protected。成员变量定为protected表示这个基类对其派生类提供了更多的灵活性,但也更加具有风险——派生类可能导致原来制定的逻辑不复存在。
    private  表示其所修饰的成员函数或成员变量只能被其自身看见(即使是其派生类也不能看见)。同样,不是“可以被看见”,而是“被用来看的”。杂货店有个租赁合同,表示店面的租用手续。对其的使用,必须十分小心,不能随便使用,故店长决定自己将其收藏好,即使后来改做小超市,请了另一个来替他打理超市的业务,也仍然由自己保管合同,打理业务的人也只能通过店长办理需要使用到租赁合同的事宜。这个租赁合同就是private的(这个比喻并不很恰当)。
    private表示只能被自己使用,private成员函数是保密的行为(如制药的秘方),private成员变量是保密的物品(如前面的租赁合同)。
    一个位图类,其可以将数字水印加到其所表示的位图中去,则生成水印的成员函数是辅助函数,而且是不打算让子类能够参与以进行改进的(虽然这不是一个好的设计),则水印的生成和抽取都应该是private的。再如多边形立体模型,多边形数组中存放的都是顶点的序号,通过顶点数组获取具体的顶点位置。在此不打算也不认为子类有改变这种关系的必要性,因此顶点数组和多边形数组都应该是private的,不过这非常明显地严重限制了子类的能动性,因此需要提供一些protected成员函数帮助处理顶点数组和多边形数组。这看起来真的比较极端,其增加的复杂性不是一般的,且又降低了效率,为此最好是将顶点数组和多边形数组单独提出来形成一个结构(结构只代表一个内存布局,但类不一样,虽然它们其实没有区别,除了缺省的限定符,一个public,一个private),然后从这个结构派生。这相当于将那两个数组定义成public,但不同。原来的基类中和这两个数组相关的成员函数又将被另外提出构成一个模板类,和那个结构一同被多重继承,这是状态和功能的分离,在ATL中被大量运用。
    看起来很荒谬,上面只不过为了一个“应该是private的”而弄得整个体系的复杂性增加,虽然代码可能并没有增多。对于这点,我只能说:最后编写代码的人是自己。


mutable

    前面提到过,在逻辑上应该是const的成员函数却仍然需要修改成员变量。为此,C++提供了mutable这个语义味浓厚的关键字。mutable用于修饰一个成员变量,以表示这个成员变量即使在const成员函数中仍可以被修改,下面给出一个具体例子。
    我曾经写过一个软件,其需要能处理几种资源(文本、声音、视频、多边形模型),我像VC6那样提供一个资源浏览栏,里面是个列表控件框,显示每个资源的图标和名字以供拖到视中进行操作。其中,对于多边形模型,图标就是那个模型的缩小,以方便对模型的选用。由于Icon的颜色和大小限制,决定选择Bitmap作为图标的表现形式。因此提供一个基类,代表资源,其具有一个如下形式:
class CResource : public CObject
{
    …
protected:
    mutable CBitmap m_BigIcon;  // 存放实例的图标
    mutable CBitmap m_SmallIcon;
public:
    virtual HBITMAP GetIcon( BOOL bBig = TRUE ) const;  // 获得特定实例的图标
    …
};
    因为获得资源实例的图标,没有改变资源实例状态的必要性,因此GetIcon是const,但是由于图标通过存放在每个实例的成员变量中以缓冲图标的使用(不用每次都新建一个位图且降低图标的管理费用——不用使用一个容器专门记录各个图标),所以将有可能修改m_BigIcon或m_SmallIcon,但它们对于资源这个概念来说根本是我私自定的,与资源无关,并不应该因为这个原因而将GetIcon的const去掉。在此,mutable的作用得到发挥,从而保证了语义。


全局、静态和成员变量

    局部变量都是临时变量,相当于草稿纸。而非临时的变量就是全局、静态和成员变量,它们的区别主要就在于作用域的不同,而从语义来看就相当于所处的名字空间不同。名字空间是一个很不错的东西,其严格说明了其包含的函数变量的意义,还可以分层嵌套以表示出更复杂的语义。
    全局变量就表示这个变量是被整个工程中的所有模块文件(即源文件,.c/.cpp)拿来用的,如MFC文档/视图结构程序中的全局应用程序对象,每个模块文件都可以使用它提取资源或执行其他操作。
    静态全局变量则表示这个变量是其所在模块文件(其定义所在的模块文件)中定义的函数(包括成员函数)公用的,不是整个工程中的函数公用的,如编写COM客户端时,某个函数创建一个组件,那个组件的CLSID就应该是静态全局兼只读(const)的变量,其不具有让工程中的其他模块文件都看见的意义(而MFC应用的应用程序对象就具有整个工程可见的意义)。
    静态成员变量则表示其是专属于其所在的类,对那个类有特殊意义,如某个MFC应用有一些配置信息,如远程服务器的名字(配置信息应该存放在注册表中,这里假设使用静态成员变量做缓冲),则对于MFC应用总有个应用程序对象,而那个远程服务器的名字应该作为这个MFC应用中的应用程序类的静态成员变量——即使多个应用的实例仍使用同一个服务器名字(实际中光是静态成员变量是达不到这个要求的)。从这个角度看,MFC应用中,所有的全局变量都应该作为应用程序类的成员变量。


断言

    断言准确的说应该算是一门语言无关的技术,不过其在代码的编写中占有重要地位,不能不提。断言就是在代码的调试版时会由于一表达式的值而弹出警告对话框,但是在释放版时不造成任何影响。断言表示在其所在位置,对应表达式的值应该满足的条件,不是可以满足的条件。
    断言的一般用途很多地方都说成是帮助调试。其实其用途和const变量及const成员函数一样,“帮助调试”只是其附加效果,它的真正目的是为了表现代码编写人的逻辑。就如前面const成员函数中所说的一样,如果一个程序员编写的代码断言失败,则表示他逻辑混乱,或者是对断言保护的代码(即断言后面的语句)进行了错误的使用,或者是断言的设置是不合逻辑的。
    在每一个类的公共成员函数的最开头都应该断言一下this的有效性(前面的Get/Set函数中我就使用了MFC中的ASSERT_VALID断言宏,后面的断言都使用MFC中的断言宏)。因为类的公共成员函数是由外界调用的,外界可能如下书写:
CAbcList *pL = NULL;
pL->GetCount();  // GetCount里断言失败
    这表示在每个公共成员函数执行以前都假定了自己的this是有效的指针,这是逻辑上的假定,因此需要用断言表示出来。但是保护及私有就不用这样保护了,因为它们一定是被自己或派生类调用,是辅助用的,而它们能够被调用,就表示调用者是有效的,逻辑上不需要前面的假定。
    CAbcList有个保护成员函数DWORD SortElement( DWORD index ) const,给定的index表示第几个元素,而返回的DWORD表示按照内定的排序方法,这个元素的位置。在SortElement里,第一句话就应该是断言index的有效性:ASSERT( index < m_Count )。这里又有个隐晦的假设,就是index一定是小于元素个数的,因此应该用断言将其表示出来。同样的,在这个方法的客户端(某个成员函数中),在使用SortElement的返回值之前,应断言以确保其小于元素个数。
    因此断言是非常重要的,其不是为了调试而写的,而是为了表现逻辑而写的,养成书写断言的习惯,将会使代码的可读性大有提高。


小结

    C++提供的语义很正常地不止上面提到的那几个,还有许多都具有很重要的语义,如虚函数,重载函数、友员及explicit关键字等,上面的只是经常会被忽视而已。最后举一个关于语义的应用例子以说明其重要性和对代码编写的指导作用。
    有个对话框的简单程序,其从COM口不断获得数据并将数据画成曲线实时显示出来。这是一个很普遍的模型(如将COM口换成编译器,就成为从编译器那里不断获得编译进度,然后再在主窗口的状态栏上实时显示出编译进度)。其有两个线程,一个工作线程负责不断获得数据并通知对话框显示数据,一个界面线程负责对话框的显示。
    现在假设使用MFC编写,对话框上有个编辑控件,用于不断显示最新的数据的真实值(如水温)。则对话框派生类中就将一个float和那个编辑控件通过DDX绑定,并存有一个数组,记录历史数据以用来画曲线。这里就产生问题了。如下的线程函数:
DWORD WINAPI ThreadProc( void *pData )  // 线程函数,用于从COM口获取数据
{
    // 数据获取循环
    // 数据获得后放在变量i中
    CAbcDialog *pDialog = reinterpret_cast< CAbcDialog* >( pData );
    ASSERT( pDialog );
    pDialog->m_Data = i;
    pDialog->UpdateData( FALSE );  // UpdateData内部ASSERT_VALID( this )断言失败
}
    注释中的调用语句断言失败,不过这并不是这个方法的失败之处,下面从语义上来分析其为什么失败,至于为什么断言失败,如果有兴趣,看参考我写的另一篇文章——《MFC界面包装类》。
    一个线程代表一个具有能动性的物体,即可以自动完成一系列任务的物体,比如自动提款机,自动流水线等。而人具有主观能动性,因此也就具备能动性,因此可以被看作一个线程。在设计一个多线程的程序时,最好就是将每个线程看成是一个人,然后就能很自然的分配工作了。
    前面的工作线程假设用A表示,界面线程用B表示。则A不断的询问COM口,是否有数据,有则将数据记录到一张卡片上,然后通过电话或按铃等手段通知B,接着继续询问COM口(这里假设没有使用COM口的中断功能)。B则在等待,一有电话或铃声就立刻看卡片(可能通过管道传到B手上,更可能的应该是使用类似电子邮件的业务),然后将数据画在看板上。
    发现问题了吗?那个卡片就相当于上面的pDialog->m_Data(准确的说应该是相当于i,这里假设i的存在仅仅是为了缓冲,而不是传输),问题就在于m_Data是B的成员,而卡片应该是A和B共同使用的,而变成B的成员后就表示A每次都需要跑到B所在的地方,将卡片填好,再回去。或者卡片仍像刚才那样用管道传递,但问题的关键是这个卡片是由A负责的,不是B,因此如果B把它弄丢了或者损坏了将由A负责再找个新的(但是在代码上没有任何问题,因为程序员不用考虑内存坏掉的情况,这种情况属于异常,而且线程永远不会闹脾气),长久下去A和B都会觉得很不公平(A:既然我负责为什么他能用?B:为什么不是我负责?)。这是正宗的权责模糊。这看起来牛角尖钻得很严重,毕竟要实现上面的算法可以使用的方法有很多,都完成同样的功能,但哪个更好呢?如果你看重语义,那么这样分析一下是值得的。
    因此上面的问题就是m_Data是CAbcDialog的公共成员,应该将其变为一静态全局变量(其只在CAbcDialog和ThreadProc之间使用。如果将ThreadProc换成CAbcDialog的静态成员函数,这将是一个大失误,这样逻辑和界面混在一起,属于不好的设计)或者将m_Data变为CAbcDialog的私有,ThreadProc只能通过一Set函数对其进行操作(削掉ThreadProc的读取权限),然后通过SendMessage将消息发个B,上面使用UpdateData来做这件事情,是不对的,表示看板也由A负责画了,则B实际什么都不干(顶多干些打杂的活,搬运看板等)。下面再来看使用语义的进一步优化。
    考虑到将数据画到看板上很轻松,这样B将长时间不干事,而A则闲不下来(要监视COM口的动向),因此想到让A每次写完卡片后不用按铃或打电话(这节约了电铃和电话的成本),而是让B闲着的时候就去看看卡片的数据是否更新了,更新了就拿回来将数据画在看板上。但如果B不是很闲,即走的不是很频繁则可能丢失数据,因此决定使用3个卡片,表示B不可能忙得会错过3个时间段。
    现在就变成m_Data[3]了,然后在B的CWinApp的派生类的OnIdle中调用pDialog->UpdateData来更新曲线。这节约了SendMessage的开销(发生线程切换,至少1000个CPU周期以上,A将挂起等待B把消息确认,而此时就将依靠COM口的缓冲来缓冲数据),将COM口的缓冲减小,因为A不会因为SendMessage的关系而错过数据(注意,不是中断模式)。如果界面的工作比较多(如界面上有个小动画,如Office的帮手),相当于看板很复杂,B并不是很闲,则错过的卡片数会增多,反而加大了代码的复杂程度,且不稳定。此时应该像原来那样使用SendMessage,不过为了消除SendMessage的开销,应该使用PostMessage来代替。
    因此当在设计多线程程序时,将每个线程看成是一个人,而代码只是人所具备的技能,然后就是自己水平的表现了。
    上面的例子只是为了说明语义在代码设计时的应用,语义准确说属于程序员的编程修养(就像编的时间多了就会使用一套自己的变量命名规则和代码书写风格),但是在代码中体现出语义不仅能使他人更易阅读代码,还能帮助自己理清思路,这在大型系统的编写中尤为重要。

关于“语义通信”的名词解释(了解语义通信必看) 语义通信的介绍 阅读详情

相关推荐

语义分割 语义分类_路面语义分割

语义分割 语义分类Hello There! This post is about a road surface semantic segmentation approach. So the focus here is on the road surface patterns, like: what kind of pavement the vehicle is driving on or if t...

weixin_26752765的博客 3415

简易的编译器——语义分析

小而简易的编译器——语义分析

随风小江~ 2472

语义通信论文略读(十九) 从语义编码到语义通信的现代通信反思

例如,在10dB的AWGN信道下,提出的蒸馏过程(即TF+Conf)实现了0.038%的字错误率,比Transformer基线(即TF)低24%,显著低于传统的单独编码-解码方法,如5位固定长度的Reed-Solomon(RS)码。随着通信技术的发展,特别是在5G和6G时代,语义感知和高效的通信方案变得越来越重要。· 技术贡献:文章不仅提出了新的概念和优势,还建立了联合语义-噪声编码(JSNC)问题的置信度蒸馏机制和强化学习(RL)驱动的语义通信范式,为下一代语义感知通信提供了新的技术贡献。

qq_54192524的博客 1477

从数组的遍历方式谈谈代码的语义性

一、前言 我之前的一篇文章介绍了几种遍历数组的方式,当然远不止这几种。不过今天想谈的是别的东西,数组遍历的具体方式和用法就不再赘述了。今天,我想以数组遍历方式为切入点,谈一下代码的语义性。当然,这只是个人理解。 首先,代码语义性是什么?从我的角度来说,语义性就是代码本身呈现的、和具体功能无关的、表达代码作用的程度,或者说是代码直观的程度。 别人看一段代码,不看代码具体的执行逻辑和过程,能理解...

weixin_42733155的博客 956

基于语义语言的语义通信(SemCom)理论:语义编码、语义解码、CSED 及语言利用

语义通信(Semantic Communication, SemCom)超越了传统 Shannon 通信范式,旨在通过语义信息的高效编码、解码及推理,实现更智能、高效的通信系统。语义编码问题关注如何将源信息(如文本、图像、传感数据)转换为具有最小语义损失的编码表示,以便高效传输。CSED(Common Semantic Error Distance)衡量的是。利用语言结构优化语义编码,使信息更易于理解和传输。利用语言建模降低 CSED,提高语义一致性。等领域提供了优化通信的基础。

qq_45540735的博客 1280

穷人的语义处理工具箱之一:语义版Jaccard

如果对工业界里的机器学习(ML)从业者进行阶级划分的话,划线标准不是你用的算法的学名听起来多酷炫,无论你手里抡着的是最潮的深度高达1000层的深度学习核炸弹,还是听起来有点掉渣的大刀长矛朴素贝叶斯,如果没有大量数据,尤其是能跑监督学习算法的带标签训练数据,你就是ML界标准的底层渣男渣女或者渣娘炮。再加上计算资源,如果贵公司有上千台GPU服务器集群可供阁下驱使,外加十几火车皮的训练数据,那你就可能成为ML界的新贵、大数据处理领域的马云。

张俊林的博客 9497

理解程序语言中的语义(Semantics)

语义是程序语言的核心组成部分,它决定了代码的行为和逻辑。无论是静态语义还是动态语义,它们都确保了程序能够按照预期执行。理解语义不仅有助于编写正确的代码,还能帮助开发者更好地调试和优化程序。

大葱的田地🌱 964

语义树索引技术

本文介绍文字语义树的索引技术。语言的基本为文字,由文字构成不同的语句,语句是文章或者人际交流最基本的语言单位。如果一句话为树的一个分支,那么相同起点的文字的语句结合在一起构成一颗语义树,树上的节点分为根节点,分支节点,果子节点(语句最后的节点,一般对应一篇文章,如果文章为果子的话,该节点为果子节点)。这样所有的语言组成不同的语义树,整个语义树表示现代的语言的语句的集合。 本文介绍一种语义树的索引技术,通过该技术找到最大匹配的语句,从而得到果子,已找到匹配的文章。 该技术可以用于全文索引、密文全文索引和NLP

newasoft 4954

值语义,引用语义对比理解

写在前面 值语义,引用语义 主要内容 值语义和引用语义的复合代表就是c++。 值语义(value sematics)指的是对象的拷贝与原对象无关,就像拷贝 int 一样。C++ 的内置类型(bool/int/double/char)都是值语义,标准库里的 complex&amp;lt;&amp;gt; 、pair&amp;lt;&amp;gt;、vector&amp;lt;&amp;gt;、map&amp;lt;&am

zhc_24的博客 2958

程序语义的深层解析:操作语义与指称语义

本文深入探讨了程序语言中操作语义与指称语义的等价性,并通过具体的编程范例来展示大步语义和小步语义的区别与联系。通过对程序执行状态的追踪和更新序列的分析,揭示了操作语义在程序执行过程中的作用。同时,通过命题证明的方式,阐述了大步语义和指称语义之间的等价性,以及小步语义在表示程序中间状态时的必要性。

weixin_35871529的博客 495

Exercise1 for Computer Organization.doc

Exercise1 for Computer Organization.doc

对象语义与值语义

一、值语义所谓值语义是一个对象被系统标准的复制方式复制后,与被复制的对象之间毫无关系,可以彼此独立改变互不影响实现 C++Java标准复制方式赋值、拷贝构造赋值,clone()基本数据类型包括整数,浮点数,布尔值,字符,指针等,全部为值语义包括整数,浮点数,布尔值,字符等,全部为值语义自定义类型不包含资源的自定义类型,系统提供的缺省拷贝构造函数与赋值操作符亦保证了值语义;包含资源的自定义类型,需要

切尔斯基 7285

语义分析程序的设计与实现

语义分析程序的设计与实现 仅供参考。 语义分析 编译原理 北邮 大三 实验要求:编写语义分析程序,实现对算术表达式的类型检查和求值。要求所分析算术表达式由如下的文法产生。 实验要求:用自底向上的语法制导翻译技术实现对表达式的分析和翻译。 (1) 写出满足要求的语法制导定义或翻译方案。 (2) 编写分析程序,实现对表达式的类型进行检查和求值,并输出: ① 分析过程中所有产生式。 ② 识别出的表达式的类型。 ③ 识别出的表达式的值。 (3) 实验方法:可以选用以下两种方法之一。 ① 自己编写分析程序。 ② 利用YACC 自动生成工具。

语义网

语义网(Semantic Web)是对未来网络的一个设想,现在与Web 3.0这一概念结合在一起,作为3.0网络时代的特征之一。简单地说,语义网是一种智能网络,它不但能够理解词语和概念,而且还能够理解它们之间的逻辑关系,可以使交流变得更有效率和价值。 语义网,它的核心是:通过给万维网上的文档 (如:HTML文档、XML文档)添加能够被计算机所理解的语义“元数据”(外语...

顺其自然~专栏 4208

Exercise3(C)

http://blog.youkuaiyun.com/lop5712/article/category/20084

CentOS 7下rsyslog日志服务器搭建全攻略:从安装到避坑

本文详细介绍了在CentOS 7系统上搭建rsyslog日志服务器的完整流程,从基础安装到高级配置,包括协议设置、日志模板设计、安全加固和性能优化。特别分享了生产环境中的实战技巧和常见问题解决方案,帮助用户高效构建可靠的日志管理系统。

happy2的博客 687

语义信息概述

无论在图像,文本,语音处理领域等,我们常看到一个词,“语义信息”。 维基百科中的解释: 语义信息(英语:semantic information)在传媒行业指语言文字提供的信息,在计算机行业指有意义的数据提供的信息,在科学哲学领域泛指任何一种有意义的语言、文字、符号、数据、公式、理论等提供的信息。语义信息的概念主要是用以区别Shannon信息的。 百度百科解释:语义信息是信息的表现形式之一,指能够消除事物不确定性的有一定意义的信息。对信息接受者来说,信息可表现为语法信息、语义信息和语用信息三个层次。语义信息

Barbara‘s Blog 9693

iperf3网络性能测试全攻略:从带宽到丢包率的实战技巧

本文提供了iperf3网络性能测试的完整实战指南,涵盖从基础部署到高级诊断的全流程。详细解析了TCP带宽测试的进阶技巧与UDP丢包率分析的深度方法,帮助网络工程师精准量化带宽、丢包率等关键指标,有效定位网络瓶颈并优化性能。

efc123456的博客 1018

SuperSonic语义层实战:如何构建统一的数据语义模型

SuperSonic作为下一代AI+BI平台,通过语义层技术将Chat BI与Headless BI完美融合,为企业提供了统一的数据语义模型解决方案。本文将深入探讨SuperSonic语义层的核心架构和实践方法,帮助你掌握构建高质量语义模型的关键技术。 ## 什么是语义层?为什么它如此重要? 🤔 语义层是位于物理数据模型和业务应用之间的抽象层,它通过定义业务术语、指标、维度以及它们之间的关系

gitblog_00666的博客 1237

基于FPGA的PCIe核系列:FPGA root模式生成工程例子分析(1)

一、 PCIE系统架构 1.1 PCIE分层结构 PCIE结构 1.2 TLP包 四种TLP类型。 Memory (内存空间操作) IO (IO空间操作) Configuration (配置操作) Message (信息操作) 四种类型TLP,如果有需要响应,称为Non-Posted TLP,如果没有需要响应,称为Posted TLP。 TLP包类型 1.2.1 TLP结构 TLP数据格式 1.2.2 Header各个字段的含义 Header格式 ...

huangshanhu的博客 3434

PostgreSQL+PostGIS实战:5分钟搞定Shapefile数据导入(附避坑指南)

本文详细介绍了如何使用PostgreSQL和PostGIS快速导入Shapefile空间数据,包括5分钟标准流程和常见问题解决方案。通过实战案例和避坑指南,帮助GIS工程师高效处理矢量数据导入中的编码、几何类型、坐标系等典型问题,提升空间数据库管理效率。

weixin_42565652的博客 400

语义Web和语义网格

现有互联网的飞速发展使它的缺陷逐渐暴露了出来,如网页功能单调、搜索引擎智能化程度低等,这是因为大部分Web上的内容是设计给人阅读的,而不是让计算机程序按其意义进行操作的。计算机能熟练地解析网页的版面,知道哪里是标题,哪里有与其他页面的链接。但是,它分辨不出个人主页和天气预报的区别,因为没有可靠的方法来处理其中的语义,没有办法智能地理解网页内容和进行操作。  语义Web就是想弥补这方面的不足,为

fireswolfs的专栏 3267

Windows系统下载安装 Git 的详细教程

本文详细介绍了Windows系统下载安装Git的完整流程,包括从Git官方网站和阿里镜像下载安装包,逐步讲解安装向导中的各个设置选项,如安装路径、默认编辑器、行尾转换、终端模拟器等,并提供了每个步骤的截图和说明。安装完成后,博客还介绍了如何验证安装是否成功,以及如何配置Git的用户名和邮箱,确保可以正常使用Git进行版本控制。

加斯顿工程师的博客 803
上一篇: C++從零開始
下一篇: developerWorks:Java 技术:重锤痛击 Robocode!
passren
博客等级 码龄24年 2粉丝 7原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值