连载36:软件体系设计新方向:数学抽象、设计模式、系统架构与方案设计(简化版)(袁晓河著)

线性化机制

 

线性关系:

两个变量之间存在一次方函数关系,就称它们之间存在线性关系。正比例关系是线性关系中的特例,反比例关系不是线性关系。更通俗一点讲,如果把这两个变量分别作为点的横坐标与纵坐标,其图象是平面上的一条直线,则这两个变量之间的关系就是线性关系。即如果可以用一个二元一次方程来表达两个变量之间关系的话,这两个变量之间的关系称为线性关系,因而,二元一次方程也称为线性方程。推而广之,含有n个变量的一次方程,也称为n元线性方程,不过这已经与直线没有什么关系了。

线性理论是目前数学领域研究的最为成熟的理论之一,特别在数学应用上具有完整的研究和应用,然而对于软件设计来说,我们虽然一直在不断使用,但是却一直没有更抽象的描述出来,很长时间内我们忽略了这个重要的机制,而本章就抛砖引玉从一些设计的事例中去窥探线性化机制在软件设计中的意义,也许能够让你大吃一惊的!

 

表驱动

 

首先让我们来看看表驱动方法,表驱动方法是一种使你可以在表中查找信息,而不必用很多的逻辑语句(ifCase)来把它们找出来的方法。事实上,任何信息都可以通过表来挑选。在简单的情况下,逻辑语句往往更简单而且更直接(来自网络的定义)。

使用表群动机制有什么优势呢?其实我们这里讲一段代码上的逻辑转换为对一个整齐划一的数据进行操作,通过统一的操作,让我们的代码变得立刻清爽起来,而且我们可以通过对数据的排列组合的处理达到对程序逻辑的更改,这种方式的变革成本是很低的。

而对于表群动机制来说,难点是如何将这些整齐划一,如何提取其共性让之达到整齐划一是关键。

我们可以将表驱动看着组合的一种扩展,表驱动具有这样的特质,其表中成员的可以根据实际情况进行任意组合的。这可能与继承有点背道而驰,但是我们应该明白,继承中其实也可以通过表驱动的方式来达到组合这样的处理,这是因为接口等概念其实也是将一个继承体系进行“整齐划一”的功能。所以,通过表驱动将这两个不同方面结合在一起。

由于接口具有这样的表驱动的的特征,所以在我们的设计模式中,比如工厂模式中就可以进一步改造,将不同的产品经过表的方式进行统一的处理。对于观察者模式来说,也是通过接口的表驱动特征将不同的观察者通过表进行注册和注销,而被观察的主体不需要区分具体的观察者类,所以能够更好的达到统一操作。

表群动机制可以应用于低层次的代码行间,也可以用于宏大的整体架构。我们使用的最大最成功的表群动机制就是关系型数据的典型应用,在关系型数据库中将数据通过规则的放置到不同字段中,然后在此基础上定义一系列独立于数据的增删查改等一系列操作,然后将这些操作使用SQL语句形成独立的语言,这样我们让数据库的设计和程序的设计进行有效的分离,两个独立进行演化和变化。

那么从关系型数据库的发展我们可以看出,在程序中的表驱动机制其实还有更好的处理优化空间,例如可以借用数据库中创建索引的方式来进行高效的访问,表中按照更高范式进行处理,则数据之间的关系会更加分离。这里不仅仅让我们的程序和数据进行有效的分离,同时让不同数据之间进行分离,这些分离其实就是分离数据与数据之间的耦合关系,让这些耦合关系通过操作算法来进行连接,这其实又让一定的耦合处理移交给程序来处理,注意这里的程序就是一些独立的程序(例如SQL语句)。所以让数据库中的表达到什么样的范式也是挺讲究的,不仅仅和效率有关,同时在耦合性方面和复杂程度来看也是需要谨慎处理的。

当然,在程序中实现表驱动可以不用完全按照关系数据的基本要求来进行处理。例如数据库中的表中无表的最基本要求。在程序中可以具有表中嵌表的处理。所以关系型数据库的设计思想是更特殊化的一种表驱动机制的实现。

在跳转条件比较复杂,数目较多的情况下,并且在采用非状态机实现时,设计会变得很复时,使用状态机实际,会简化系统的设计,提高代码的质量与可靠性。

在跳转比较简单,数目较少的情况下,并且整个系统也比较容易使用非状态机实现的情况下,使用状态机设计,会增加资源的开销(主要在组合逻辑资源上),并且代码量也比较大。

需求是逐渐增加,系统是越来越复杂,修改成本,升级成本等等原因,什么时候是从无状态机向有状态机设计的时机呢?所以对于接口,最好不体现状态机(不体现状态)因为这会增加升级的失败率和成本,无状态接口是解除相互之间的耦合的比较好的方式。

状态自动传递优点:

ü 对象间依赖关系是固定的,不需要修改就能支持今后需求。

ü 对象间依赖关系被隐藏在对象内部,不必暴露给外部。

ü 易于实现相关对象状态的一致性。

ü 降低应用开发难度,外部故障只需要通知直接相关的对象即可,内部在根据依赖关系自动将状态传送到全部相关对象。

状态迁移表:创建一个描述迁移的数据表,该表被一个处理事件的引擎解释,引擎查找与事件相匹配的迁移,调用相应的工作,并更改状态,好处是状态机的逻辑全部集中在一个地方并没有被动作实现污染,维护比较容易,可以容易的在运行时改变迁移表,其主要确定是速度,对于较大的状态机来说,遍历表的时间相当长,其次是需要写很多额外的代码来维护迁移表。

表实现状态机和state模式的区别:state模式对与状态相关的行为进行建模,而表驱动的方法着重于定义状态转换。

从另一个更加深入的研究我们知道:表驱动机制其实就是数学中的线性代数,我们应用表驱动的方法将我们的处理业务完全的线性化的处理。其理论来源就是表驱动的处理过程是将一些非主要特征进行忽略或去除,然后将主要特征进行整齐划一,而这个过程就是将系统线性化的处理过程。经过线性化处理后的数据,在既定的规则中是不具有本质的区别,只是一些数据取值的不同表示,所以才能将这些元素装入一个表中进行保存。

 

线性化的特点

 

那么线性化处理在系统科学中有什么好处呢?这些好处对于我们的设计思想有什么更加好的提示和帮助呢?

首先,线性具有加和性,这种加和性的意义就是:线性关心表示互不相干的独立作用,例如将AB同时作用于系统,等于他们分别作用于系统之和,不会因为AB同时输入的相互影响而产生相干(联合)效应,不会在A+B以外有所增益或损耗。

而软件设计中追求的低耦合高聚合特性,对于表群动机制,或者说线性代数的叠加性来说,不是完美的一致吗?所以是否能够让我们程序进行线性化也就成了我们解耦的一个方向,换句话说,如果我们让我们的程序代码线性化了,那么我们的解耦也达到一定的成果和层次。

其次具有齐次性,齐次性不是加和性的简单扩展,齐次性意味如果在系统中将输入倍化,输出也将同样的倍化,不会发生定性的、结构性的质变。

对于加和性和齐次性等叠加特性来说,对于我们的代码在性能方面也是一个非常好的基础,由于系统之中的不会产生相干效应,同时不会更改其性质和结构,不会发生不可预知的质的变更,所以就适用于大规模的并行处理,所以在大数据处理中,更加有效的将线性方式的融入将更加有助于进行大规模的并行设计和开发。

但是我们要注意,线性的这种叠加性只能满足有限的叠加和,而不能推广到无线的叠加和,同时这些叠加是在某一个层次上的叠加,而不能超越层次进行叠加,所以在我们的不同置换层面上,由于其基础不一致,有些是基础,而有些是涌现以后的结果,两者叠加就是“牛头不对马嘴”了。

当然我们在检测是否是线性中的叠加,我们有可用通过不同数量级别的多个输入和输出来判断是否是线性增加,所以其检测方法也是清晰明了的。

当然在上面我们提到关系数据库是线性的一个绝好的例子,那为什么目前我们在处理大数据的时候还在去SQL呢?这里大家需要注意:部分的线性不等于整体的线性,我们的线性系统只是从一个系统中抽离出线性的特征,而对于整体系统来说,肯定存在非线性的原因。我们不能将所有线性部分进行相加,就得到整体线性,部分的线性在质上是不同的,关注点是不一样的。虽然可能同时线性,但是领域不同,线性具体体现方式不同,不能将这些进行简单相加。

SQL语句中主要的操作包括:选择、投影、连接、并、交、差、增加、删除、修改、查询等操作这些操作主要是体现在对集合和对数据的操作行为。上面谈到关系型数据库不是一种线性化的处理操作,那为什么没有线性代数中的一些运算呢?例如内积、外积、矩阵变换、行列式运算、求秩、求逆等等运算呢?这主要是目前我们的SQL操作还只是针对每一条记录进行的运算,这些记录和记录之间存在的相互关系还没有进一步获得处理。如果能够建立这些记录和记录之间的关系(例如内积,可判断其相似程度)那么我们就可以将这些运算扩展到关系数据库的运算之中。而这也是目前进行大数据挖掘、人工智能方面的研究领域。同时,此时一条记录就可以看待成一个向量,多个向量之间进行聚集形成一类或者一个领域,在数学上就是一个矩阵,通过矩阵中的记录进行数值化,就可以进行一系列的线性代数的运算。

在系统中,我们也可以通过线性回归针对不同的变量进行线性化处理,这里主要涉及的是在进行量化一个复杂系统中的有效的处理方法。虽然针对软件设计来说其帮助不是很大,但是对于系统分析来说,意义非凡。

 

线性化的现实难度

 

当然,表驱动也面临重重困难,其也有自身的限制和所适应的环境。这里主要体现在以下的一些方面:

非线性特征很强,在处理环境中很难进行线性化的处理。实际上能够进行线性化的场景不是很普遍,因为现实场景中真正具有线性的区间非常的少,在图形中,线性代表的是一些直线的处理,只要涉及到曲线和具有断点的直线或者直线组合在进行线性化处理的过程就非常复杂,往往在使用了线性处理以后,反而无法适应非线性的变化。在软件设计方面,从大数据的分析就可见一斑,为什么大数据很难使用关系型数据表来表示呢?就是因为数据与数据之间很多都是非线性的,具有在不同层次上的关系,而且对应关系都不仅仅局限于函数中的一对一、多对一的关系,而是多对多的关系,这样的关系首先体现的就是多值函数的领域,就更不用说是可以进行近似的线性处理。所以,对于能够进行线性处理或者线性近似的地方一定使用表驱动,如果脱离了场景,则一定要规避线性化的冲动。

很难一次性的考虑所有的变化因素,软件设计过程中,永远无法准确预测未来的变化,所以也不能一次性的将所有变化因素完全考虑。在进行线性化设计过程中,由于是进行有限的近似处理,所以有很多因素我们认为将来可以忽略不计,但是往往计划赶不上变化。将来这个忽略因素很可能成为主要的原因,此时就容易导致原有设计的崩溃。在关系型数据库的设计中也处处出现这样的情况,最简单的就是新增或者删除一列,还有变化最猛烈的是此表设计跟不上变化,需要变更此表和其他表的关系。而这对于系统的兼容性、系统升级以及维护都带来无法估量的风险。

不合理的表驱动反而画蛇添足,在进行整齐划一的过程中,有时候容易将数据分裂成不合理的一些组合关系,此时数据反而被肢解破碎,无法通过数据之间的关系来代替算法逻辑。或者由于设计不足导致数据本身没有在形式上的整齐划一,而导致不得不在算法上进行一些特殊的处理,所以,进行有效的表驱动设计还是一个“技术活”,需要对本系统或者本特性有比较深入的理解以后才能进行更好的设计。

线性关系本身的特征导致了其在此进行相加也不会更改事物的本质,这是一个优点也是一个缺点,对于一些需要通过组合变化涌现新特征的环境就不能设计成表驱动的处理,例如一些人工智能、数据检索等系统中,此时虽然可以将某一个部分进行线性化,但是整体上需要经过不断的反馈机制以及非线性的处理来完成其发生质变。

从上面可以看出分离程序和数据的表驱动是如此优秀,能够给人一兴奋的感觉。然而,我们追根溯源到线性化这一本质特征,感觉依然意犹未尽。是的,其实不仅仅是表驱动的应用,对于系统本身,其实也是可以进行线性化的手法来进优化我们的系统。

在系统里面,为了更好的规整我们的系统,也常常采用线性化的处理。最直接的设计模式就是“过滤器”模式。在过滤器模式中,将其输入和输出进行规范化(一般采用的方法是继承同一个接口),然后再讲这些过滤器挂接在一起,而只是对输入和输出的规范化就是一种线性化的处理。这样无论挂接多少过滤器都是线性叠加的,不会随着过滤器的增加而发生质的变化。同时,过滤器之间也是相互独立,不会由于其他过滤器的引入而发生耦合。所以过滤器模式是一种耦合性很低的架构模式。

在泛型化编程中,迭代器就体现了通过访问形式来完成对不同数据结构体进行的线性化访问的处理,迭代器按照访问方式不同划分为:前向迭代器、索引迭代器、双向迭代器、随机访问迭代器,虽然这些迭代器根据不同容器结构划分成不同的类型,但是,这些迭代器是将访问方式进行线性化的统一,通过线性化的处理保证使用者只依赖于线性化方式,而不依赖于特殊化的处理(例如对树或图的不同访问方式)。然而,为了满足迭代器的处理操作,必须满足不同种类迭代器的操作符的重载处理,然而针对树或者图这样复杂的处理时候,不同的算法却又决定了访问的顺序以及是否能否访问等一系列问题。

通过正交分解来解决耦合,正交化分解是解决耦合的一种极端的处理方式,其解耦以后带来的效果也是煞是惊人的。因为在不同的维度上,相互之间的耦合度为0。而要达到正交分解的第一步就是将这些变量进行线性化,只有线性化后才能进行正交处理。

这里我们也可以看到,线性化以后的组织有多种,反映到数据结构上,可以形成线性表也可以形成树的结构,其实树的节点也可以看做进行线性化处理的一个结果。

从上面可知,线性化处理后,我们其实正在进行一种分离的操作,就是将数据和操作进行分离,而此时这里所谓的“数据”,在软件设计的线性化过程中很多时候就是“代码”,或者是置换的结构,这又反过来让代码数据化(这的确非常有意义,我们很多时候是将数据代码化,例如大部分的算法),通过代码的数据化过程以后,我们就可以实施上面中的线性化的数学抽象过程。

 

正交

 

正交化:

正交化是将属于相同本征值的没有相互正交的函数重新线性组合为新的相互正交的函数的过程。

矩阵的正交分解:

矩阵的正交分解是指A分解为一个正交矩阵Q和一个对角可逆上三角矩阵R的乘积。

正交处理是一种线性化重新组合运算。正交化的结果就是产生特性之间的正交(数学的多维空间中为“垂直”的相互关系,在向量的角度上,即两个向量的内积为0)。对于软件开发来说,其相互耦合的两个特性(对应数学中的向量),其相互之间的耦合降低到最小,这也是进行系统模块化或者特性开发的最终目标。最近以来,有一种敏捷开发的实践为“特性开发”,其基本思想就是利用正交的结果将系统划分成不同的特性,特性与特性之间相互独立,对于每一个特性开发就是一个“小平台”,而产品仅保持一个版本分支(即使在多个不同应用场景的产品系列),由此通过开发效率最高效的软件工程方法来进行软件版本管理。在这个实践中其关键中的关键就是如何让特性之间形成线性化的正交。其中目前所能支撑并现有的技术就是面向方面(又翻译为面向切面)的编程方法(AOP)。

面向方面编程- Aspect Oriented Programming(AOP),AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。

ü 接合点 (Joinpoint) — 代码中定义明确的可识别的点。

ü 切点 (Pointcut) — 通过配置或编码指定接合点的一种方法。

ü 通知 (Advice) — 表示需要执行交叉切割动作的一种方法

ü 混入 (Mixin) — 通过将一个类的实例混入目标类的实例引入新行为。

应用AOP的主要目的----尽量分离“技术问题实现”和“业务问题实现”

ü 它允许开发者能够对横切关注点进行模块化设计----“切面”的意义在于将业务逻辑中复杂问题分离成不同层面,使其实现统一集中的管理。

ü 能够实现分散关注,将通用需求功能从不相关类之中分离出来。这样将能够更好地遵守“单一职责”原则;

ü 同时,能够实现代码重用。一旦行为发生变化,不必修改很多类,只要修改共享的类。

面向切面编程其重要的意图就是如何在面向对象(OOP)的基础上如何更进一步使用线性化的处理机制。并且让独立处理的特性具有正交的属性,所以,AOP所最为成功的例子就是包括日志、安全这样的正交更为彻底的业务的实现。当然AOP不仅仅局限于线性化机制,其还包含有更多的技术,然而,如果无法做到线性化的正交处理,其面向切面编程一定为不合理的设计方式。同时,从线性化的方面再加上我个人的意见来看,AOP还远远没有更好的利用线性化的各种优势特征,在上面的线性化的数学抽象中我们也会看到其具有更多的技术特征来应该不断改造现在的设计和实现方法或技术。

 

线性化与非功能属性

 

在进行了线性化处理以后,其系统的处理性能虽然可能不是最优,但是其性能也具有线性特征,也就是可控或可衡量,在增加或者减少数据量的情况下,是满足线性的量化关系。而且,线性化处理后进行优化也是具有简单的优势,例如我们可以进行一些简单的修改就可以将计算放置到多线程、多核或者分布式计算中进行处理,这样让整个处理变得流程化,能够在此进行更强大的高并发处理,以此大大利用了资源而提高系统的性能。

同时,线性化与可扩展性、和可重用性的关系也变得非常简单,只需要关系是否满足线性规则,更多的耦合变化成为数据与数据的先后顺序,或者更有甚者连位置都变得不再重要。于是可以达到“任意”扩展和收缩,让系统的耦合变成了数据之间的联系而不用在程序设计和实现进行考虑的巨大优势。

另外,线性化与可配置的关系也变得非常简单,配置变成了简单的选择或者不选择的两个操作,而且还可以在系统运行过程中,动态地进行配置而满足实际的需求。而且可以在变更数据的情况下进行程序运行的配置,这也是线性化带给我们的“绝佳”灵活性的影响。程序的运行不再依赖于静态的代码,而是根据数据的差异来决定,于是可以在数据层面上展开各种“特殊化”的处理,此在上面线性化的数学抽象章节就有“闪亮”的体现。

 

线性化与体系结构

 

冯诺依曼体系结构以及其在此基础上进一步改进的哈佛体系结构,它们也同时展示线性化处理框架。在这些体系结构中,无论计算和寻址都是采用线性方式在处理。首先我们来看看其总线模型,总线是一组传送线路以及相关的总线协议总和,总线首先经过线性规划以后,通过不同的线性化地址信息(一般是基于分段化处理的地址信息),不同的设备只要能够满足接口的基本定义(物理电气、时钟等接口要求),就能够挂接到这个总线上,由于是线性化的,所以不同设备之间不需要了解到其他挂接到总线的设备信息,所有的挂接设备都是独立的,相互不相关,互不影响,所有的设备不需知道自己是如何控制的,可能是一个或者多个总线控制器控制和协调不同的设备,也可能为了提高效率而采用AMD的设备来进行控制和协调。采用线性化处理能够极大的提高并发处理,能够极大简化系统结构,让系统结构在逻辑上非常清晰明了,并且具有充分的可扩展性。同时由于这样的线性独立特点,也直接应用到交换设备的不同分布结构,而诸如星型、树形拓扑结构都是通过建立在单条总线上的线性化结构而建立起的多维度的处理信息的能力,这样达到对复杂情况(超越总线结构)的有效处理。

由于体系结构下的线性方式,所以在一些缓存处理过程中也体现了使用线性处理的特点,由于线性化对于系统分层有很多优势,由此分层情况下就涉及到不同层次级别的数据设备如何能够进行更高效的处理,由此缓存产生了,如果所缓存的数据按照线性化规则聚集,那么可以通过数据的特征值,成块地将数据加载到缓存区,这样能够更加有效的提高访问效率和命中率,反之,如果数据本身缺少线性化结构,那么数据之间就存在更多的耦合,此时可能会在不同的条件分支中去访问不同区域的数据,这样就很难计算到底缓存那部分数据为热点数据,由此缓存的功效就降低。总的来说,使用线性化的数据可以让我们的缓存策略变得更加容易,无论是导入还是脏数据导出,都会变得更加简单。

 

线性化的优势

 

线性化的物理意义主要满足了在操作和管理成本最小化原则。就如同光线在空间传播以最短路径为准则一样,对于一个软件设计来说,操作和管理成本最小化是一个极限趋近的准则体现。线性化的处理,在外部体现上就能够因为整齐划一而降低其运作成本。通过线性化处理以后,我们能够很容易在其操作上进行大规模的并行操作。例如在一些大型机的并行方案中的流水线处理方案中,首先将操作限定为取指令、译码、执行三个不同的过程,所有的指令都遵守这样的过程。如果所执行的指令的结果不需要不同流水线相互访问,相互之间是独立的线性关系,那么我们就可以在此基础上进行大规模的并行处理,而且不需要考虑执行过程中不需要考虑其中出现中断也影响其他流水线的效率。这样通过线性化处理以后其在时间上将会成倍的缩减,而且在很多时候,当不存在线性的情况下,比如我们将任务划分的长度不均等,操作过程中流水线之间相互干扰,也需要通过线性规划来进行近似的处理。

通过上面的一些简单理解,我们将线性化的一些优势进行总结:

ü 使用线性化有利于分层和分区域,无论在横向或纵向方面使用线性化都会为我们达到更好的分离处理,为什么使用线性化的方法就能够更好的完成分层或分区域呢?最主要是目前在线性化处理方面的研究是最充分的,这些通过线性化分离的个体是更容易组合在一起。而且我们目前无论是冯诺依曼体系结构还是哈弗体系结构其实都是按照线性化机制来设计的,所以在这样的系统中的软件设计上使用线性化机制是自然而然的事情。

ü 有利于多种不同线性划分共存一起而又无相互耦合,比如我们的段页式的设计,两种不同的线性处理办法能够非常融洽的共处,因为线性方式就存在线性独立性,而线性独立性是目前所发现独立程度最高的方式。

ü 有利于模块化和组件化,由于耦合度最低,所以能够更好的模块组件这些特性,因此在更大更广泛的系统设计中,能够达到更加灵活的设计决策。这就好比通过规则的砖块能够架构高楼大厦一样,如果采用非规则的结构,可能需要更大的成本来构建大厦了。

ü 有利于将处理的程序转化为数据进行处理,然后通过通用的处理方式来代替各种特殊的处理。这里最好的例子就是数据库的数据表,我们可以通过将数据进行线性化处理而在其上通用的处理(集合的处理),就能够代替我们的程序进行判断和分支的处理。

ü 有利于迭代化的处理,以及对其群体的快速遍历,通过线性化处理以后,其进行大规模的数据操作将会变得更加的高效,可以通过选择不同特征的迭代器进行统一的处理。

那么与软件设计相关的处理中,又有哪些方法和策略来进行线性规划呢?或者说通过什么方式来进行线性约束呢?

线性化方式由于相互关联非常简单,能够进行很好的形态上的扩展,但是,线性化有一个比较致命的缺点就是执行效率,由于结构简单,所以在提升效率方面不得不进行一些多余的操作,或者给出一些冗余的算法优化操作,例如,为了能够更好的进行查找,可能需要先对原始的线性数据进行一次排序,然后使用折半等让人烦恼的算法来进行查找,而这恰恰违背了我们进行开发的一个准则:尽量使用合适的数据结构来代替我们采用精良的算法。因为精良的算法很难具有高的适应性和有效的扩展性,如果能够使用静态的数据结构解决问题,则优先使用数据结构来解决,因为这是静态的方式,其复杂度不会跟随运行进行动态变化,这样满足了另一个准则:如果能够使用静态方式完全能够适应需求,那么我们就优先采用静态方式进行解决。

所以,如果发现线性化方式很难解决问题的时候,不妨使用循环线性表、树结构、图结构等来进行分析,或者分不同层次,不同步骤的方式来解决问题。

固然,线性化机制能够很简化我们的相关设计,但是对于由于在进行线性化处理过程中,就保留了我们认为重要的关系,而忽略或者删除了非重要的关系。但是,如果我们一开始就无法明确知道什么是重要的关系,什么又是非重要的关系的时候,使用线性化机制就会导致错误和失败。例如,在一些大数据分析过程中,其数据与数据的相互关系,本来就隐含在大量的数据之中,在没有进行分析之前,我们是无法判断其准确的有效性,这就有点像粒子物理中的不确定性原理,所以我们只能通过对所有的数据按照一定的算法进行分析,最后才能给出一个更大概率成立的结论。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值