**關係運算子**在計算機科學的編程語言中，是測試或定義兩個實體之間某種關係的構造或操作符。一共有六种關係，分别为：`小于`、`大于`、`小于等于`、`大于等于`、`等于`和`不等于`。在具備布爾型別的編程語言中（如 Pascal，Ada 或 Java），這些運算符通常根據兩個操作變量之間的條件關係是否成立，判定為真或假。諸如 C 語言中關係運算子返回整數 0 或 1，其中 0 表示假，任何非零值表示真。使用關係運算子創建的表達式，形成所謂的關係表達式或條件。
關係運算子可以被視為謂詞邏輯的特殊情況。

相等性
---

### 用法

在許多編程語言構造和資料型別中都使用到相等性，它用於測試元素是否已存在於集合中，或者藉由鍵來存取值。它在切換（switch）語句，以及編程的邏輯併聯過程中，用於將控制流調度到正確的分支。相等性的可能含義之一是"如果 a 等於 b，那麼我們可以在任何上下文中互換 a 或 b，而不會產生任何差異。"但這樣的聲明不一定成立，尤其在可變性和內容等同性一起考慮時。

### 物件相等與內容等同性

有時，特別是在物件導向編程中，對資料型別和繼承物件進行比對時，出現了相等性和辨別的問題。以下情況通常需要區別：

* 相同型別的兩個不同物件，例如兩隻手
* 兩個物件相等但不同，例如兩張10元鈔票
* 兩個物件相等但有不同的呈現，例如$1元紙鈔和$1元硬幣
* 對同一物件的兩個不同參照，例如，同一人的兩個暱稱

在許多現代編程語言中會藉由參照來存取物件和資料結構。在這些語言中，需要測試兩種相等性質：

* 實質同等性：如果有兩個參照A和B來自引用同一個物件，以A與物件進行的互動，跟藉由B與物件進行的互動，兩者其實就是相同作用而無法區別，特別是以A去改變物件的異動會反映在B之上。當討論為值而非物件時，實質同等性並不適用。
* 語義同等性：如果兩個參照物件或兩個值在某種意義上是等價的：
	+ 結構等式（即它們的內容是相同的），或淺薄地（僅測試目前部份）或深入地（遞歸地測試其所有部份的相等性）。實現這一點的簡易方法是通過代表等式：檢查參照的值是否有相同的代表式。
	+ 其它特制的同等性，保留外部行為。例如將{\displaystyle {\frac {1}{~{}2~{}}}}和{\displaystyle {\frac {2}{~{}4~{}}}}視為有理數時，被判斷是相等的。除了反射性、對稱性和傳遞性之外，對 A = B 特制的定義可能是"若且唯若對於物件A和物件B之上的所有操作，都將具有相同的結果時，則 A = B "。

第一種同等性質通常蘊涵著第二種同等性質（除了非數字類（not a number, NaN），它們不等於自身），但反向的同等性質並不一定成立。例如兩個字串物件可以是不同物件（第一種意義不相等），但它們包含相同的字元序列（第二種意義上相等）。有關此問題的更多信息，請參閱識別（identity）。

實數中包括許多簡分數，無法以浮點算數精確地表示，所以需要在給定誤差範圍內來測試相等性。但這樣的誤差範圍將打破一些例如傳遞性、反身性的要求性質：IEEE浮點標準是判斷 Nan ≠ NaN 成立（NaN不等於自身）。

其他編程元素例如可計算的函數，可能沒有相等性的意義，或者相等性是不能計算的。由於這些原因，一些語言以基礎類別、介面、特點（trait）或協定的形式，定義了"可比較"的明確概念，以源碼中的顯式聲明，被藉由型別的結構，來使用關係運算。

### 比較不同類型的值

JavaScript，PHP 和一些其它動態型別的語言中，如果兩個值相等，等號運算符將計算為真，即使它們實際上為不同型別的物件，例如以數值4和字串"4"相比較，結果會是相等。在這類語言中通常也會提供型別相等運算子，僅對具有相同或等價型別的物件比較返回真（在PHP 5中 4 ==="4"為假，但 4 =="4" 為真）。而在將數值0也當作布爾值為假的編程語言中，該運算子可化簡為檢查物件是否為數值零（例如，對於數值0或字串"0"的x物件，使用型別相等運算子，則 x == 0 判斷傳回真值）。

次序比較
----

非數值資料的次序比較（大於或小於）運算是根據排序慣例（例如字串依照編程語言內定的字典次序，和/或可由開發人員設定的）。當兩個資料項 a 和 b 之間的比較結果，要和數值關聯時，通常慣例是如果 a < b 則結果賦值為 -1，如果 a = b 則為 0，如果 a > b 則為 1。例如C語言的函數`strcmp`執行三方向比較，並根據此慣例返回 -1, 0 或 1，而`qsort`預期比較函數依此慣例返回值。在排序演算法中比較方法源碼的效率至為關鍵，因為它是排序性能的主要因素之一。

開發人員定義的資料型別（不是編程語言內建的型別）的比較，可以編寫自訂的或使用函式庫的函數（如上文的`strcmp`）來執行，或者在某些語言中通過重載比較運算符-即以開發人員的定義指派給比較運算子，來比較特定資料型別。另一個選擇是使用某些慣例，例如成員比較。

邏輯等價
----

雖然一開始可能不那麼顯而易見，像布爾邏輯運算符 XOR，AND，OR 和 NOT，這些關係運算子可以設計為具有邏輯等同性，使得它們都可以相互定義。對於任何給定的 x 和 y 值，以下四個條件語句都有相同的邏輯等價性 E（全為真或全為假）：

{\displaystyle E={\begin{cases}x<y\\y>x\\x\ngeq y\\y\nleq x\end{cases}}}
這依賴於域是良好排序的。

標準關係運算符
-------

在編程語言中最常見到的數值關係運算子如下所示。

Common relational operators| Convention | *equal to* | *not equal to* | *greater than* | *less than* | *greater thanor equal to* | *less thanor equal to* |
| --- | --- | --- | --- | --- | --- | --- |
| In print | = | ≠ | > | < | ≥ | ≤ |
| FORTRAN | `.EQ.` | `.NE.` | `.GT.` | `.LT.` | `.GE.` | `.LE.` |
| ALGOL 68 | `=` | `≠` | `>` | `<` | `≥` | `≤` |
| `/=` | `>=` | `<=` |
| `**eq**` | `**ne**` | `**gt**` | `**lt**` | `**ge**` | `**le**` |
| APL | `=` | `≠` | `>` | `<` | `≥` | `≤` |
| BASIC-like, spreadsheet formulas | `=` | `<>` | `>` | `<` | `>=` | `<=` |
| MUMPS | `=` | `'=` | `>` | `<` | `'<` | `'>` |
| Lua | `==` | `~=` | `>` | `<` | `>=` | `<=` |
| Pascal-like | `=` | `<>` | `>` | `<` | `>=` | `<=` |
| C-like | `==` | `!=` | `>` | `<` | `>=` | `<=` |
| Bourne-like shells | `-eq` | `-ne` | `-gt` | `-lt` | `-ge` | `-le` |
| Batch file | `EQU` | `NEQ` | `GTR` | `LSS` | `GEQ` | `LEQ` |
| MATLAB | `==` | `~=` | `>` | `<` | `>=` | `<=` |
| `eq(x,y)` | `ne(x,y)` | `gt(x,y)` | `lt(x,y)` | `ge(x,y)` | `le(x,y)` |
| Fortran 90 | `==` | `/=` | `>` | `<` | `>=` | `<=` |
| Mathematica | `==` | `!=` | `>` | `<` | `>=` | `<=` |
| `Equal[x,y]` | `Unequal[x,y]` | `Greater[x,y]` | `Less[x,y]` | `GreaterEqual[x,y]` | `LessEqual[x,y]` |

1. ↑  Including FORTRAN II, III, IV, 66 and 77.
2. ↑  ALGOL 68: *stropping* regimes are used in code on platforms with limited character sets (*e.g.*, use `>=` or `GE` instead of `≥`), platforms with no `**bold**` emphasis (use `'ge'`), or platforms with only UPPERCASE (use `.GE` *or* `'GE'`).
3. ↑  Including Visual Basic .NET, OCaml, SQL, Standard ML, Excel, and others.
4. ↑  Including ALGOL, Simula, Modula-2, Object Pascal (Delphi), OCaml, Standard ML, Eiffel, APL, and others.
5. ↑  Including C, C++, C#, Go, Java, JavaScript, Perl (numerical comparison only), PHP, Python, Ruby, and R.
6. ↑  Including Bourne shell, Bash, Korn shell, and Windows PowerShell. The symbols `<` and `>` are usually used in a shell for redirection, so other symbols must be used. Without the hyphen, is used in Perl for string comparison.
7. ↑  MATLAB, although in other respects using similar syntax as C, does not use `!=`, as `!` in MATLAB sends the following text as a command line to the operating system. The first form is also used in Smalltalk, with the exception of equality, which is `=`.
8. ↑  Including FORTRAN 95, 2003, 2008 and 2015.

其他較少見的：Common Lisp的不等關係運算子是 /=，Macsyma/Maxima 的不等關係運算子是 #。舊的Lisp使用equal，greaterp 和 lessp; 而以not運算子作邏輯否定。

語法
--

關係運算子也用於技術文獻而不是單詞，如果編程語言支援通常以中綴表示法，亦即出現在其操作變量（兩個表達式是相關的）之間。
舉例而言如果 x 小於 y，在Python中的表達式將印出句子：

```
if x < y:
    print("x is less than y in this example")

```

其他編程語言如 Lisp 使用前綴表示法，如下所示：

```
(>= X Y)

```

### 操作符鏈接

鏈接關係在數學中是普遍的寫法，例如 3 < x < y < 20 表示 3 < x 而且 x < y 而且 y <20。語義是很清楚的，因為數學中這些關係運算是有傳遞性的。然而，許多最近的編程語言會把 3 < x < y 的表達式，看作兩個左（或右）關係運算子的組合，而解譯為`(3 < x ) < y`。如果我們設 x = 4 則得到`(3 < 4 )< y`，而運算式變成`true < y`，這是無意義的。但它卻可能通過 C/C++ 和一些其它語言的編譯（因為 true 會以數值1代表）。

有些編程語言如Python和Perl 6 能正確給出`x < y < z`表達式所代表的數學意義，其它種語言則不，
部份是因大多數運算符在C語言種類中，以中綴表示法的運作方式有所不同。D編程語言保持與C的一些兼容性，而"允許C語言表達式卻有微妙不同的語義（雖然可說是方向正確），與便利性比起來造成更多的混淆"。

有些語言如 Common Lisp，對此則使用多參數謂詞。當 *x* 在 1 和 10 之間時，評估比較運算式
`(<= 1 x 10)`結果為真。

### 與賦值運算子的混淆情況

早期（西元1956-57年）FORTRAN編程語言受限於有限的字集，其中等號"="是唯一的關係運算子，沒有數學上通用的大於"<"或小於">"關係符號（當然也就沒有不大於"≤"或不小於"≥"之類的關係符號），迫使設計者定義如`.GT.`、`.LT.`、`.GE.`、`.EQ.`這樣的關係符號，隨後等號"="字符被人借用來執行複製，儘管此用法與數學意義明顯不一致（X = X + 1 在數理是不能成立的）。

因此國際代數語言（IAL，ALGOL 58）和 ALGOL（1958和1960）引入了":="表示賦值操作，留下等號"="字符作為相等關係的標準，遵循這個慣例的編程語言有CPL，ALGOL W，ALGOL 68，BCPL，Simula，SET（SETL），Pascal，Smalltalk，Modula-2，Ada，Standard ML，OCaml，Eiffel，Object Pascal（Delphi），Oberon，Dylan，VHSIC（VHDL）等。

#### B 和 C 編程語言

大多數編程語言遵循的這種事實標準，後來被名為B的極簡編譯語言間接改變。它唯一的應用目標是作為（一個非常原始的）Unix的最初移植版本，但它也演變成非常有影響力的 C 編程語言。

B 最初是系統編程BCPL的語法變體，簡化（無型別）的CPL版本。在描述為 "拆解" 過程的情況下，BCPL的交集和聯集運算子被替換為`&`和`|`（後來變成`&&`和`||`）。

同樣的過程中，原來具有ALGOL風格在BCPL語言中表示賦值操作的`:=`符號，在B語言中被替換為`=`。導致這種演變過程的原因未知。由於變量賦值在B語言中沒有特殊語法（例如 let 或類似），而在表達式中允許這個操作，所以等號的傳統語義（相等關係）和非標準涵義（變量賦值）另外相關聯在一起。為了區分這兩種意義，因此Ken Thompson使用了特別的雙等號`==`組合取代相等關係判斷。

一個小的型別系統後來被引入，B接著演變成C。C語言的普及與Unix的關聯，使Java，C＃和許多其他語言沿用這種語法，雖然已經大不相同於等號的數學關係涵義。

#### 編程語言

C編程的賦值語句會有返回值，由於任何非零值在條件運算式中被解譯為真，源碼`if(x = y)`是合法的，但與`if(x == y)`的意義完全相異。前者語義為"將 y 賦值給 x，如果 x 的新值不為 0，則執行以下語句";後者語義則為"如果僅當 x 等於 y，執行以下語句"。

```
 int x = 1;
 int y = 2;
 if (x = y) {
 /\* This code will always execute if y is anything but 0\*/
 printf("x is %d and y is %d\n", x, y);
 }

```

雖然Java和C＃具有與C相同的運算子，但這種錯誤通常會導致這些編程的編譯錯誤，因為條件式必須是布林型別，而且沒有隱式方法能從其它類型（如數值）轉為布林型別。
因此，除非被賦值的變量具有布林型別（或包裝為布林型別），否則會產生編譯錯誤。

ALGOL類的語言中例如Pascal，Delphi和Ada（允許其編程可定義嵌套函數），Python和許多函數語言中，賦值運算子不可出現在表達式中（包括if子句），排除了這種錯誤。一些編譯器如GNU編譯器集合（GCC），則在編譯`if`語句中包含賦值運算子的源碼時，提供了警告，雖然在if條件中可以有一些賦值的合法使用。在此情況下賦值語句必須對額外的括號特別聲明，以避免警告。

同樣地，一些語言如BASIC使用"="等號同時代表賦值操作和相等關係兩者，因為在語法上它們是分開的（如Pascal，Ada，Python等，賦值運算子不能出現在表達式中）。

有些程序員習慣於逆向（一般從左到右條件判斷）寫一個常數的比較：

```
 if (2 == a) { /\* Mistaken use of = versus == would be a compile-time error \*/
 }

```

如果意外使用了`=`，因為 2 不是變量則源碼的編譯無效，編譯器會產生一個錯誤訊息，指出在等號的位置應該以適當的運算子替換。這種編程寫法被稱為左手比較或尤達條件式。

下表列出了各種編程測試型別相等的不同機制：

| Language | Physical equality | Structural equality | Notes |
| --- | --- | --- | --- |
| ALGOL 68 | `a :=: b` *or* `a *is* b` | `a = b` | when `a` and `b` are pointers |
| C, C++ | `a == b` | `*a == *b` | when `a` and `b` are pointers |
| C# | `object.ReferenceEquals(a, b)` | `a.Equals(b)` | The `==` operator defaults to `ReferenceEquals`, but can be overloaded to perform `Equals` instead. |
| Common Lisp | `(eq a b)` | `(equal a b)` |  |
| Go | `a == b` | `reflect.DeepEqual(*a, *b)` | when a and b are pointers |
| Java | `a == b` | `a.equals(b)` |  |
| JavaScript | `a === b` | `a == b` | when a and b are two string objects containing equivalent characters, the === operator will still return true. |  |
| OCaml, Smalltalk | `a == b` | `a = b` |  |
| Pascal | `a^ = b^` | `a = b` |  |
| Perl | `$a == $b` | `$$a == $$b` | when `$a` and `$b` are references to scalars |
| PHP5 | `$a === $b` | `$a == $b` | when `$a` and `$b` are objects |
| Python | `a is b` | `a == b` |  |
| Ruby | `a.equal?(b)` | `a == b` |  |
| Scheme | `(eq? a b)` | `(equal? a b)` |  |
| Swift | `a === b` | `a == b` | when a and b have class type |
| Visual Basic .NET | `a Is b` or `object.ReferenceEquals(a, b)` | `a = b` or `a.Equals(b)` | Same as C# |
| Objective-C (Cocoa, GNUstep) | `a == b` | `[a isEqual:b]` | when `a` and `b` are pointers to objects that are instances of `NSObject` |

1. ↑  Patent application: On May 14, 2003, US application 20,040,230,959  "IS NOT OPERATOR" was filed for the `ISNOT` operator by employees of Microsoft. This patent was granted on November 18, 2004.

另見
--

* 二元關係
* 等於(數學)
* 邏輯運算子
* 等号