比较运算

顾名思义,这类运算旨在对两个操作数进行比较,并根据比较条件是否成立而返回逻辑特性值 truefalse

下表给出了所有比较运算及其特性,如使用的符号、优先级、示例和结合性。

优先级

符号

说明

示例

结合性

6

<

小于

e1 < e2

6

>

大于

e1 > e2

6

<=

小于等于

e1 <= e2

6

>=

大于等于

e1 >= e2

7

==

等于

e1 == e2

7

!=

不等于

e1 != e2

每种运算的原理是使用列(包含列的说明)中的标准对两个操作数进行比较。例如,x < y 条目表示检查“x 小于 y”是否成立。相应的,如果 x 确实小于 y,那么比较结果为 true,否则为 false

可对任何类型的操作数进行比较(对于不同类型,会进行 类型强制转换 )。

考虑到左结合性且返回结果是 bool 类型,构造一系列比较可能不会取得明显效果。例如,假设有一个表达式用于检查 y 值是否介于 xz 的值之间,如下所示:

int x = 10y = 5z = 2;
bool range = x < y < z;   // true (!)

但是,这样的表达式会以另外一种方式处理。甚至编译器会对此进行标记并发出警告:“运算中未安全使用 'bool' 类型”。

根据左结合性,首先检查左侧条件 x < y,其结果会作为 bool 类型的临时值替换到后续表达式中,从而得到:b < z。然后将 z 的值与临时变量 b 中的 truefalse 进行比较。要检查 y 的范围是否介于 xz 之间,需使用两个比较运算并要结合逻辑运算“与”(将在 下一节中介绍)。

int x = 10y = 5z = 2;
bool range = x < y && y < z;   // false

进行“等于/不等于”比较时,应考虑操作数类型的特征。例如,浮点数在计算后通常包含“近似”值(我们之前介绍过 doublefloat 的精度,详见 实数一节)。例如,严格来说,0.6 与 0.3 之和不等于 0.9:

double p = 0.3q = 0.6;
bool eq = p + q == 0.9;        // false
double diff = p + q - 0.9;     // -0.000000000000000111

差值是 1*10-16,但如此小的差值也足以让比较运算返回 false。

因此,比较实数的“等于/不等于”关系时,应基于其差值与可接受偏差,通过“大于”/“小于”运算符完成,这种偏差可根据计算特性手动确定,也可采用通用偏差。回顾一下,对于 doublefloat 类型,系统定义了嵌入式精度常量 DBL_EPSILON 和 FLT_EPSILON,这两个常量适用于值 1.0。要与其他值进行比较,必须对这两个常量进行缩放。在 ExprRelational.mq5 脚本中,给出了 isEqual 函数的一种可能实现来进行实数比较,其中就考虑了这一点。

bool isEqual(const double xconst double y)
{
   const double diff = MathAbs(x - y);
   const double eps = MathMax(MathAbs(x), MathAbs(y)) * DBL_EPSILON;
   return diff < eps;
}

这里我们使用获得无符号绝对值的函数 (MathAbs) 和取两个值中较大值的函数 (MathMax)。将在第四章的 数学函数 一节中介绍这些内容。使用 < 运算,将 isEqual 函数参数之间的绝对差值与 eps 变量中的校准公差进行比较。

切勿使用此函数与绝对零进行比较。要与绝对零进行比较,可以采用以下方法(可能需要根据你的具体需求进行一定调整):

bool isZero(const double x)
{
   return MathAbs(x) < DBL_EPSILON;
}

按字典顺序比较字符串,即逐个字母进行比较。将每个字符的代码与第二个字符串中相同位置字符的代码进行比较。一直进行比较,直到发现代码中的差异或其中一个字符串结束。字符串大小关系等于第一个出现的不同字符的大小关系,若出现的字符都相同,则认为较长的字符串大于较短的字符串。切记,同一个字母的大小格式对应的代码不同,表示大写字母的代码小于表示小写字母的代码(很奇怪吧)。

空字符串 ""(实际上存储一个终止符 0)不等于特殊值 NULL,后者表示没有字符串。

bool cmp1 = "abcdef" > "abs";     // false, [2]: 's' > 'c'
bool cmp2 = "abcdef" > "abc";     // true,  by length
bool cmp3 = "ABCdef" > "abcdef";  // false, by case
bool cmp4 = "" == NULL;           // false

此外,MQL5 还提供了一些用于比较字符串的函数,将在 处理字符串一节中介绍这些函数。

在进行“等于/不等于”比较时,不建议使用 bool 常量: truefalse。这是因为,在类似 v == truev == false 的表达式中,v 操作数可以被直观的解释为逻辑类型,而实际上它是一个数字。我们知道,数字中的零逻辑上被视为 false,而所有其他值都被视为 true(我们经常借此来表示某个结果存在或不存在)。但在这种情况下,类型强制转换会反向:truefalse 被“扩展”为数字类型 v,实际上分别等于 1 和 0。这种比较的结果将不同于预期(例如,100 == true 的比较结果为假)。