コンピュータサイエンス において、関係演算子とは、 2つのエンティティ間の関係を構文的に定義するプログラミング言語構造または演算子です。これには、数値の等価性(例:5 = 5)や不等価性(例:4 ≥ 3)が含まれます。
Pascal、Ada、Python 、 Javaなど、型システムに明確なブールデータ型が含まれるプログラミング言語では、これらの演算子は通常、2 つのオペランド間の条件関係が成立するかどうか に応じて true または false に評価されます。
Cなどの言語では、関係演算子は整数0 または 1 を返します。0 は false を表し、0 以外の値は true を表します。
関係演算子を用いて作成された式は、いわゆる関係式または条件を形成します。関係演算子は、論理述語の特殊なケースと見なすことができます。
等価性は、多くのプログラミング言語の構成要素やデータ型で使用されています。集合内の要素が既に存在するかどうかをテストしたり、キーを介して値にアクセスしたりするために使用されます。また、switch文では制御フローを適切な分岐にディスパッチするために、また論理型プログラミングでは単一化処理の際に使用されます。
等価性には複数の有効な定義があり、特定の言語は様々な設計上の側面に応じて、それらの1つ、あるいは複数の定義を採用する可能性があります。等価性の一つの意味は、「a がbと等しい場合、aとb はどのような文脈においても違いを意識することなく互換的に使用できる」というものです。しかし、この記述は必ずしも当てはまりません。特に、可変性と内容の等価性の両方を考慮すると、この記述は当てはまりません。
特にオブジェクト指向プログラミングにおいては、比較によってデータ型や継承、等価性、同一性といった問題が生じることがあります。多くの場合、以下の点を区別する必要があります。
多くの現代のプログラミング言語では、オブジェクトやデータ構造は参照を介してアクセスされます。このような言語では、2種類の等価性をテストする必要があります。
通常、最初のタイプの等価性は2番目のタイプの等価性を意味します(非数(NaN)のように、それ自体と等しくないものを除く)。しかし、逆は必ずしも真ではありません。例えば、2つの文字列オブジェクトは、異なるオブジェクト(最初の意味では等しくない)であるにもかかわらず、同じ文字列(2番目の意味では等しい)を含む場合があります。この問題の詳細については、 同一性を参照してください。
多くの単純な分数を含む実数は、浮動小数点演算では正確に表現できないため、与えられた許容範囲内で等価性をテストする必要がある場合があります。しかし、そのような許容範囲は、推移性などの望ましい特性を容易に破る可能性があり、反射性も破る場合があります。IEEE浮動小数点標準では、NaN ≠ NaNが成立することを要求しています。対照的に、正値演算(正値支持者はIEEE浮動小数点数を置き換えることを意図しています)の(2022)プライベート標準では、同様の概念であるNaR(Not a Real)が採用されており、NaR = NaRが成立します。[ 1 ]
計算可能関数などの他のプログラミング要素は、等価性の概念を持たないか、あるいは計算不可能な等価性しか持たない場合があります。こうした理由から、一部の言語では、基底クラス、インターフェース、特性、またはプロトコルといった形で「比較可能」という概念を明示的に定義しています。これらの概念は、ソースコード内で宣言することによって明示的に使用されるか、または関連する型の構造を通じて暗黙的に使用されます。
JavaScript、PHP、VBScript、その他いくつかの動的型付け言語では、標準の等価演算子はいわゆる緩い型付けに従います。つまり、2つの値が等しくなく互換性のない型であってもtrueと評価されますが、言語固有の規則によって互いに強制的に型変換することができ、例えば数値4はテキスト文字列「4」と等しくなります。このような動作は通常、言語を使いやすくするためのものですが、多くのプログラマが気づいていない、予想外の結果や予測困難な結果につながる可能性があります。例えば、JavaScriptの緩い等価規則により、等価性が非推移的になったり(つまり、a == band b == c、but a != c)、特定の値がその値の否定と等しくなったりすることがあります。[ 2 ]
これらの言語では厳密な等価演算子もよく利用でき、同一または同等の型の値に対してのみ true を返します(PHPでは、4 === "4"はtrueですが、4 == "4"はfalseです)。[ 3 ] [ 4 ]数値0がfalseと解釈される可能性のある言語では、この演算子によってゼロのチェックなどが簡素化されることがあります(x == 0型に依存しない等価演算子を使用すると、xが0または「0」のどちらであってもtrueになります)。
数値以外のデータの大なり小なりの比較は、プログラミング言語に組み込まれているか、プログラマによって構成可能な ソート規則 (テキスト文字列の場合は辞書式順序など) に従って実行されます。
2つのデータ項目(例えばaとb )の比較結果に数値を関連付けたい場合、通常の慣例では、 a < b の場合は -1、 a = b の場合は 0、 a > b の場合は 1 を代入します。例えば、C関数は3者間比較をstrcmp実行し、この慣例に従って -1、0、または 1 を返します。qsortは、比較関数がこの慣例に従って値を返すことを期待しています。ソートアルゴリズムにおいて、比較コードの効率はソート性能を左右する重要な要素の一つであるため、非常に重要です。
プログラマ定義データ型(プログラミング言語が組み込みで認識できないデータ型)の比較は、カスタム関数やライブラリ関数(strcmp上記参照)によって実行できます。また、一部の言語では比較演算子のオーバーロード(つまり、比較するデータ型に応じてプログラマ定義の意味を割り当てる)によって実行できます。別の方法としては、メンバー単位の比較などの規約を使用する方法があります。
一見すると分かりにくいかもしれませんが、ブール論理演算子XOR、AND、OR、NOTと同様に、関係演算子も論理的等価性を持つように設計することができ、相互に定義することができます。以下の4つの条件文は、任意のx値とy値に対して、すべて同じ論理的等価性E(すべて真またはすべて偽)を持ちます。
これは、ドメインが適切に順序付けられていることに依存します。
プログラミング言語で最も一般的に使用される数値関係演算子を以下に示します。標準SQLではBASICと同じ演算子が使用されますが、多くのデータベースでは標準の演算子!=に加えて、以下の演算子も使用できます。SQLは厳密なブール代数に準拠しており、以下のほとんどの言語で一般的に使用される短絡評価は使用しません。例えばPHPは短絡評価を使用しますが、それ以外は多くのSQLデータベースと同様に、これら2つの演算子がエイリアスとして定義されています。 <>
| 大会 | 等しい | 等しくない | より大きい | 未満 | より大きいか等しい | 以下 |
|---|---|---|---|---|---|---|
| 印刷中 | = | ≠ | > | < | ≥ | ≤ |
| FORTRAN [注 1 ] | .EQ. | .NE. | .GT. | .LT. | .GE. | .LE. |
| ALGOL 68 [注 2 ] | = | ≠ | > | < | ≥ | ≤ |
/= | >= | <= | ||||
eq | ne | gt | lt | ge | le | |
| APL | = | ≠ | > | < | ≥ | ≤ |
| BASIC、ML、Pascal [注 3 ] | = | <>[注4 ] | > | < | >= | <= |
| Cのような[注5 ] | == | != | > | < | >= | <= |
| おたふく風邪 | = | '= | > | < | '< | '> |
| ルア | == | ~= | > | < | >= | <= |
| アーラン | == | /= | > | < | >= | =< |
=:= | =/= | |||||
| ボーン型シェル[注6 ] | -eq | -ne | -gt | -lt | -ge | -le |
| バッチファイル | EQU | NEQ | GTR | LSS | GEQ | LEQ |
| ooRexx、REXX | = | ¬= | > | < | >= | <= |
\= | ||||||
<> | ||||||
| MATLAB [注 7 ] | == | ~= | > | < | >= | <= |
eq(x,y) | ne(x,y) | gt(x,y) | lt(x,y) | ge(x,y) | le(x,y) | |
| Fortran 90、[注8 ] Haskell | == | /= | > | < | >= | <= |
| マセマティカ[ 5 ] | == | != | > | < | >= | <= |
Equal[x,y] | Unequal[x,y] | Greater[x,y] | Less[x,y] | GreaterEqual[x,y] | LessEqual[x,y] |
>=にまたはGEを使用するなど)、強調≥のないプラットフォーム( を使用する)、または大文字のみのプラットフォーム(または を使用する) のコードで使用されます。bold'ge'.GE'GE'#<>!=!=その他の慣習はあまり一般的ではありません。Common LispとMacsyma / Maximaは、数値に対してBasicのような演算子を使用します。ただし、不等号はCommon LispとMacsyma/Maximaの両方で使用されます。Common /=Lispには、、、、、など#、異なる目的で使用される複数の等号演算子と関係演算子のセットがあります。[ 6 ]古いLispでは、、、、 ;が使用され、残りの演算子にはを使用してそれらの否定が行われました。 eqeqlequalequalpstring=equalgreaterplesspnot
関係演算子は、技術文書でも単語の代わりに使用されます。プログラミング言語でサポートされている場合、関係演算子は通常、中置記法で記述されます。つまり、関係演算子はオペランド(関係する2つの式)の間に記述されます。例えば、Pythonの式は、xがyより小さい場合、次のメッセージを出力します。
if x < y : print ( "この例ではxはyより小さいです" )Lispなどの他のプログラミング言語では、次のように接頭辞表記法が使用されます。
( >= X Y )数学では、3 < x < y < 20(3 < xかつx < yかつy < 20を意味します)のように、関係演算子を連結することが一般的です。数学におけるこれらの関係演算子は推移的であるため、構文は明確です。
しかし、最近の多くのプログラミング言語では、3 < x < y のような式は2つの左(または右)結合演算子で構成されていると解釈され、 のように解釈されます(3 < x) < y。x=4 とすると となり(3 < 4) < y、評価すると となりますが、true < yこれは一般的には意味をなさないものです。しかし、C/C++などの一部の言語ではコンパイルされ、驚くべき結果が得られます(ここではtrue は数値 1 で表されるため)。
式に馴染みのある数学的な意味を与えることは可能であり、PythonやRakux < y < zなどの一部のプログラミング言語ではそれが可能です。一方、C#やJavaなどではそうではありません。これは、C言語系言語における他の多くの中置演算子の動作と異なることが一因です。D言語はC言語との互換性をある程度維持しているため、そのようなことはしません。「C言語の式を(おそらく正しい方向への変更ではありますが)微妙に異なる意味合いで許容することは、利便性よりも混乱を招くことになるでしょう」[ 7 ] 。
Common Lispなどの一部の言語では、このために複数の引数述語を使用します。Lispでは、(<= 1 x 10)x が1から10の間の場合、は真となります。
初期のFORTRAN(1956~1957年)は、文字セットが厳しく制限されており、関係=演算子は のみでした。<または(そしてまたは>は当然存在しませんでした)は存在しませんでした。そのため、設計者は、、などの記号を定義する必要に迫られ、数学的な用法とは明らかに矛盾しているにもかかわらず、残りの文字をコピーに使用してしまいがちになりました(は不可能であるはずです)。 ≤≥.GT..LT..GE..EQ.=X=X+1
国際代数言語 (IAL、ALGOL 58 ) およびALGOL (1958 および 1960) が:=割り当て用に導入され、標準が=同等に利用可能になりました。この規則には、CPL、ALGOL W、ALGOL 68、 Basic Combined Programming Language ( BCPL )、Simula、 SET Language ( SETL )、Pascal、Smalltalk、Modula-2、Ada、Standard ML、OCaml、Eiffel、Object Pascal ( Delphi )、Oberon、Dylan、 VHSIC ハードウェア記述言語 ( VHDL )、およびその他のいくつかの言語が従っています。
ほとんどのプログラミング言語におけるこの統一された事実上の標準は、Bというミニマリストなコンパイル言語によって間接的に変化しました。B の唯一の用途は、当時非常に原始的だったUnixの最初の移植版の媒体としてでしたが、後に非常に影響力のあるC言語へと発展しました。
B はシステムプログラミング言語BCPLの構文を変更した変種として始まり、 CPLの簡素化された(型なし)バージョンでした。いわゆる「ストリップダウン」プロセスで、BCPL [ 8 ]andの演算子と が(後にそれぞれ とになりました。[ 9 ] )に置き換えられました。同じプロセスで、B では ALGOL スタイルの BCPL が に置き換えられました。このすべての理由は不明です。[ 10 ] B では変数の更新に特別な構文 ( や など) がなく、式の中で許可されていたため、等号のこの非標準的な意味は、等号の従来の意味を別の記号に関連付ける必要があることを意味しました。ケン・トンプソンは、このために アドホックな組み合わせを使用しました。or&|&&||:==let==
その後、小さな型システムが導入され、B は C になりました。この言語の人気と Unix との関連性により、等号の数学的意味との不必要な矛盾にもかかわらず、Java、C#、その他多くの言語が構文的にはこれに追随しました。
C言語における代入は値を持ち、条件式ではゼロ以外のスカラー値はすべて真と解釈されるため、[ 11 ]コードは有効ですが、とは意味が大きく異なります。前者のコードは「yをxに代入し、 xの新しい値がゼロでない場合は次の文を実行する」という意味です。後者のコードは「xがyと等しい場合のみ、次の文を実行する」という意味です。[ 12 ]if (x = y)if (x == y)
int x = 1 ; int y = 2 ; if ( x = y ) { // このコードは、 y が 0 以外の場合は常に実行されます。printf ( "x is %d and y is %d \n " , x , y ); }JavaとC#にはCと同じ演算子がありますが、これらの言語ではこの誤りは通常コンパイルエラーを引き起こします。これは、if条件式は 型である必要があり、他の型(例えば数値)を 型にboolean変換する暗黙的な方法がないためです。したがって、 に代入される変数が 型(またはラッパー型)でない限り、コンパイルエラーが発生します。 booleanbooleanBoolean
Pascal、Delphi、AdaなどのALGOL系言語(ネストされた関数定義が可能な点)、Python、そして多くの関数型言語などでは、代入演算子は式(節を含む)に出現できないため、この種のエラーは発生しません。GNUコンパイラコレクションif(GCC)などの一部のコンパイラは、if文内に代入演算子を含むコードをコンパイルする際に警告を発しますが、if条件式内で代入演算子を使用する正当な方法もいくつかあります。そのような場合、警告を回避するには、代入演算子を明示的に括弧で囲む必要があります。
同様に、 BASICなどの一部の言語では、代入と=等価性は構文的に分離されているため、代入と等価性の両方に記号のみを使用します(Pascal、Ada、Python などでは、代入演算子は式に出現できません)。
プログラマーの中には、定数との比較を通常の順序とは逆に記述する習慣を持つ人がいます。
// = と == の誤った使用はコンパイル時エラーになりますif ( 2 == a ) { // ... }を誤って使用した場合=、2は変数ではないため、結果として得られるコードは無効になります。コンパイラはエラーメッセージを生成し、適切な演算子に置き換えることができます。このコーディングスタイルは、左手比較、またはヨーダ条件と呼ばれます。
この表には、さまざまな言語でこれら 2 種類の等価性をテストするためのさまざまなメカニズムがリストされています。
| 言語 | 身体的平等 | 構造的平等 | 注記 |
|---|---|---|---|
| アルゴル68 | a :=: bまたはa is b | a = b | aと がbポインタである 場合 |
| C、C++ | a == b | *a == *b | aと がbポインタである 場合 |
| C# | object.ReferenceEquals(a, b) | a.Equals(b) | 演算子==はデフォルトで になりますが、代わりにを実行するようにオーバーロードReferenceEqualsできます。 Equals |
| コモンリスプ | (eq a b) | (equal a b) | |
| アーラン | a =:= b | a == b | aとbが数値の場合 |
| フォートラン | associated (pa, b) | a == b | paはポインタです |
| 行く | a == b | reflect.DeepEqual(*a, *b) | aとbがポインタの場合 |
| ジャワ | a == b | a.equals(b) | |
| JavaScript | a === b | a == b | a と b が同等の文字を含む 2 つの文字列オブジェクトの場合でも、=== 演算子は true を返します。 |
| OCaml、Smalltalk | a == b | a = b | |
| パスカル | a^ = b^ | a = b | |
| パール | $a == $b | $$a == $$b | $aと が$bスカラーへの参照である 場合 |
| PHP | $a === $b | $a == $b | $aと が$bオブジェクトである 場合 |
| パイソン | a is b | a == b | |
| ルビー | a.equal?(b) | a == b | |
| スキーム | (eq? a b) | (equal? a b) | |
| 迅速 | a === b | a == b | aとbがクラス型を持つ場合 |
| Visual Basic .NET [不等式 1 ] | a Is bまたはobject.ReferenceEquals(a, b) | a = bまたはa.Equals(b) | C#と同じ |
| Objective-C ( Cocoa、GNUstep ) | a == b | [a isEqual:b] | と はa、bインスタンスであるオブジェクトへのポインタです。NSObject |
ISNOTRuby では、 はa === b「b はセット a のメンバーである」という意味で使用されますが、メンバーであることの意味の詳細は、関係するデータ型によって大きく異なります。===は、ここでは「case 等価」または「case 包含」演算子として知られています。