Các phép so sánh
Như tên gọi của nó, các phép toán này nhằm mục đích so sánh hai toán hạng và trả về một tính năng logic, true
hoặc false
, tùy thuộc vào điều kiện cần giữ trong phép so sánh.
Bảng dưới đây cung cấp tất cả các phép toán so sánh và thuộc tính của chúng, chẳng hạn như ký hiệu được sử dụng, mức độ ưu tiên, ví dụ và tính kết hợp.
P | Biểu tượng | Mô tả | Ví dụ | A |
---|---|---|---|---|
6 | < | Nhỏ hơn | e1 < e2 | L |
6 | > | Lớn hơn | e1 > e2 | L |
6 | <= | Nhỏ hơn hoặc bằng | e1 <= e2 | L |
6 | >= | Lớn hơn hoặc bằng | e1 >= e2 | L |
7 | == | Bằng | e1 == e2 | L |
7 | != | Không bằng | e1 != e2 | L |
Nguyên tắc của mỗi phép toán là so sánh hai toán hạng bằng cách sử dụng tiêu chí từ cột chứa mô tả của nó. Ví dụ, mục nhập "x < y"
có nghĩa là kiểm tra xem "x có nhỏ hơn y"
hay không. Tương ứng, kết quả so sánh sẽ là true
nếu x
thực sự nhỏ hơn y
và false
trong tất cả các trường hợp khác.
Phép so sánh có tác dụng với các toán hạng của bất kỳ kiểu nào (đối với các kiểu khác nhau, sẽ thực hiện ép kiểu).
Xem xét tính kết hợp bên trái và kết quả trả về của kiểu bool
, việc xây dựng một chuỗi so sánh không hoạt động rõ ràng như vậy. Ví dụ, một biểu thức giả định để kiểm tra xem giá trị y có nằm giữa các giá trị x
và z
hay không, có vẻ như có thể xuất hiện như sau:
int x = 10, y = 5, z = 2;
bool range = x < y < z; // true (!)
2
Tuy nhiên, biểu thức như vậy được xử lý theo cách khác. Ngay cả trình biên dịch cũng phân biệt nó bằng cảnh báo: "sử dụng không an toàn kiểu 'bool' trong hoạt động".
Do tính kết hợp trái, điều kiện trái x < y
được kiểm tra trước, và kết quả của nó được thay thế dưới dạng giá trị tạm thời của kiểu bool vào biểu thức như sau: b < z
. Sau đó, giá trị của z
được so sánh với true
hoặc false
trong biến tạm thời b
. Để kiểm tra xem y
có nằm trong khoảng x
và z
hay không, bạn nên sử dụng hai phép toán so sánh kết hợp với phép toán logic AND
(sẽ được xem xét trong phần tiếp theo).
int x = 10, y = 5, z = 2;
bool range = x < y && y < z; // false
2
Khi sử dụng phép so sánh để so sánh bằng/không bằng, các đặc điểm của các kiểu toán hạng sẽ được xem xét. Ví dụ, các số dấu phẩy động thường chứa các giá trị "xấp xỉ" sau khi tính toán (chúng ta đã xem xét độ chính xác của việc biểu diễn double
và float
trong phần Số thực). Ví dụ, tổng của 0,6 và 0,3 không phải là 0,9:
double p = 0.3, q = 0.6;
bool eq = p + q == 0.9; // false
double diff = p + q - 0.9; // -0.000000000000000111
2
3
Sự khác biệt tạo ra 1*10^-16
, nhưng đủ để phép so sánh trả về kết quả sai.
Do đó, các số thực nên được so sánh về sự bằng nhau/bất bằng nhau bằng cách sử dụng các toán tử lớn hơn/nhỏ hơn cho sự khác biệt và độ lệch chấp nhận được của chúng được sắp xếp thủ công, dựa trên các tính năng của phép tính hoặc được thực hiện theo một phép tính chung. Hãy nhớ rằng đối với double
và float
, các hằng số độ chính xác nhúng, DBL_EPSILON
và FLT_EPSILON
, được xác định, hợp lệ cho giá trị 1.0
. Chúng phải được chia tỷ lệ để so sánh các giá trị khác. Trong tập lệnh ExprRelational.mq5
, một trong những hiện thực hóa có thể có của hàm isEqual
được trình bày để so sánh các số thực, xem xét khía cạnh này.
bool isEqual(const double x, const double y)
{
const double diff = MathAbs(x - y);
const double eps = MathMax(MathAbs(x), MathAbs(y)) * DBL_EPSILON;
return diff < eps;
}
2
3
4
5
6
Ở đây chúng ta sử dụng hàm để lấy giá trị tuyệt đối không dấu (MathAbs
) và giá trị cao nhất trong hai giá trị (MathMax
). Chúng sẽ được mô tả trong phần Hàm toán học của Phần 4. Sự khác biệt tuyệt đối giữa các tham số của hàm isEqual
được so sánh với dung sai được hiệu chuẩn trong biến eps bằng phép toán <
.
Dù sao thì hàm này cũng không thể được sử dụng để so sánh với số không tuyệt đối. Với mục đích này, bạn có thể sử dụng cách tiếp cận sau (có thể cần phải điều chỉnh một chút cho phù hợp với nhu cầu cụ thể của bạn):
bool isZero(const double x)
{
return MathAbs(x) < DBL_EPSILON;
}
2
3
4
Các chuỗi được so sánh theo thứ tự từ điển, tức là từng chữ cái một. Mã của mỗi ký tự được so sánh với mã của ký tự ở cùng vị trí của chuỗi thứ hai. Việc so sánh được thực hiện cho đến khi tìm thấy sự khác biệt trong các mã hoặc một trong các chuỗi kết thúc. Tỷ lệ chuỗi sẽ bằng với tỷ lệ của các ký tự khác biệt đầu tiên hoặc chuỗi dài hơn sẽ được coi là lớn hơn chuỗi ngắn hơn. Hãy nhớ rằng các chữ cái viết hoa và viết thường có các mã khác nhau và lạ thay, các chữ cái viết hoa có mã nhỏ hơn các chữ cái viết thường.
Một chuỗi rỗng ""
(thực tế, nó lưu trữ một giá trị đầu cuối là 0) không bằng giá trị đặc biệt của NULL
, nghĩa là không có chuỗi nào.
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
2
3
4
Hơn nữa, để so sánh các chuỗi, MQL5 cung cấp một số hàm sẽ được mô tả trong phần Làm việc với chuỗi.
Khi so sánh để tìm sự bằng nhau/bất bằng nhau, không nên sử dụng hằng số bool: true
hoặc false
. Vấn đề là, trong các biểu thức như v == true
hoặc v == false
, toán hạng v
có thể được diễn giải trực quan như một kiểu logic, trong khi thực tế, nó là một số. Như đã biết, giá trị bằng không được coi là false
trong các số, trong khi tất cả các giá trị khác được diễn giải là true
(chúng ta thường muốn sử dụng nó như một dấu hiệu cho thấy một số kết quả có hoặc không có). Tuy nhiên, trong trường hợp này, ép kiểu sẽ đi ngược lại: true
hoặc false
được "mở rộng" thành kiểu số v
và thực sự trở thành tương ứng bằng 1
và 0
. Phép so sánh như vậy sẽ có kết quả khác với kết quả mong đợi (ví dụ, phép so sánh 100 == true
sẽ trở thành false
).