相等性
用法
在許多程式語言構造和資料型別中都使用到相等性,它用於測試元素是否已存在於集合中,或者藉由鍵來存取值。它在切換(switch)語句,以及編程的邏輯並聯過程中,用於將控制流調度到正確的分支。相等性的可能含義之一是“如果 a 等於 b,那么我們可以在任何上下文中互換 a 或 b,而不會產生任何差異。但這樣的聲明不一定成立,尤其在可變性和內容等同性一起考慮時。
物件相等與內容等同性
有時,特別是在面向對象編程中,對資料型別和繼承物件進行比對時,出現了相等性和辨別的問題。以下情況通常需要區別:
•相同型別的兩個不同物件,例如兩隻手
•兩個物件相等但不同,例如兩張10元鈔票
•兩個物件相等但有不同的呈現,例如$1元紙鈔和$1元硬幣
•對同一物件的兩個不同參照,例如,同一人的兩個暱稱
在許多現代程式語言中會藉由參照來存取物件和數據結構。在這些語言中,需要測試兩種相等性質:
•實質同等性:如果有兩個參照A和B來自引用同一個物件,以A與物件進行的互動,跟藉由B與物件進行的互動,兩者其實就是相同作用而無法區別,特別是以A去改變物件的異動會反映在B之上。當討論為值而非物件時,實質同等性並不適用。
•語義同等性:如果兩個參照物件或兩個值在某種意義上是等價的:
•結構等式(即它們的內容是相同的),或淺薄地(僅測試目前部分)或深入地(遞歸地測試其所有部分的相等性)。實現這一點的簡易方法是通過代表等式:檢查參照的值是否有相同的代表式。
•其它特製的同等性,保留外部行為。例如將和視為有理數時,被判斷是相等的。除了反射性、對稱性和傳遞性之外,對 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(全為真或全為假):
這依賴於域是良好排序的。
語法
關係運運算元也用於技術文獻而不是單詞,如果程式語言支援通常以中綴表示法,亦即出現在其操作變數(兩個表達式是相關的)之間。 舉例而言如果 x 小於 y,在Python中的表達式將印出句子:
其他程式語言如 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#和許多其他語言
沿用這種語法,雖然已經大不相同於等號的數學關係涵義。