Операции сравнения

Как и следует из названия, данные операции предназначены для сравнения двух операндов и возврата логического признака — true или false — в зависимости от выполнения условия в сравнении.

В таблице приведены все операции сравнения и их свойства: используемые символы, приоритеты, примеры и ассоциативность.

П

Символы

Описание

Пример

А

6

<

Меньше

e1 < e2

L

6

>

Больше

e1 > e2

L

6

<=

Меньше или равно

e1 <= e2

L

6

>=

Больше или равно

e1 >= e2

L

7

==

Равно

e1 == e2

L

7

!=

Не равно

e1 != e2

L

Принцип работы каждой операции — сравнение двух операндов с помощью критерия из колонки с описанием. Например, запись "x < y" означает проверку на то, что "x меньше y". Соответственно, результат сравнения будет равен true, если x действительно меньше y, и false — во всех остальных случаях.

Сравнения работают для операндов любых типов (при различии типов делается их приведение).

С учётом левой ассоциативности и возврата результата типа bool, построение цепочки сравнений работает не столь очевидным образом. Например, гипотетическое выражение для проверки того, лежит ли величина y между значениями x и z, могло бы, казалось бы, выглядеть так:

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

Однако такое выражение обрабатывается иначе. Даже компилятор выделяет его предупреждением "небезопасное применение 'bool'" ("unsafe use of type 'bool' in operation").

В силу левой ассоциативности сначала проверяется левое условие x < y, и его результат в виде временного значения типа bool подставляется в выражение, которое становится таким: b < z. Далее значение z уже сравнивается с true или false во временной переменной b. Для того чтобы проверить, лежит ли y в диапазоне между x и z, следует использовать две операции сравнения, объединенных логической операцией И (она будет рассмотрена в следующем разделе).

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

При использовании проверок на равенство и неравенство следует учитывать особенности типов операндов. В частности, числа с плавающей запятой часто содержат "приблизительные" значения после вычислений (мы рассматривали точность представления double и float в разделе Вещественные числа). Например, сумма 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.

Поэтому проверки вещественных чисел на равенство и неравенство следует проводить с помощью операций больше/меньше для их разницы и допустимого отклонения, которое подбирается вручную, исходя из особенностей расчетов, или берется универсальное. Напомним, что для double и float определены встроенные константы точности 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) — они будут описаны в 4-й части в разделе Математические функции. Абсолютная разница между параметрами функции 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,  по длине
bool cmp3 = "ABCdef" > "abcdef";  // false, по регистру
bool cmp4 = "" == NULL;           // false

Кроме того, для сравнения строк MQL5 предоставляет несколько функций, которые будут описаны в разделе Работа со строками.

При проверке равенства и неравенства не рекомендуется использовать константы bool: true и false. Дело в том, что в выражениях вида v == true или v == false операнд v может интуитивно интерпретироваться как логический тип, будучи на самом деле числом. Как известно, для чисел нулевое значение расценивается как false, а все остальные — как true (это зачастую хочется использовать, как признак наличия какого-то результата или отсутствия). Однако в данном случае приведение типов к общему происходит в обратную сторону: true или false "расширяются" до числового типа v и становятся фактически равны 1 и 0 соответственно. Такое сравнение будет иметь результат, отличный от предполагаемого (например, ложным получится сравнение 100 == true).