関係演算子

コンピュータサイエンス において、関係演算子とは、 2つのエンティティ間の関係を構文的に定義するプログラミング言語構造または演算子です。これには、数値の等価性(例:5 = 5)や不等価性(例:4 ≥ 3)が含まれます。

PascalAdaPython 、 Javaなど、型システムに明確なブールデータ型が含まれるプログラミング言語では、これらの演算子は通常、2 つのオペランド間の条件関係が成立するかどうか に応じて true または false に評価されます。

Cなどの言語では、関係演算子は整数0 または 1 を返します。0 は false を表し、0 以外の値は true を表します。

関係演算子を用いて作成された式は、いわゆる関係式または条件を形成します。関係演算子、論理述語の特殊なケースと見なすことができます。

平等

使用法

等価性は、多くのプログラミング言語の構成要素やデータ型で使用されています。集合内の要素が既に存在するかどうかをテストしたり、キーを介して値にアクセスしたりするために使用されます。また、switch文では制御フローを適切な分岐にディスパッチするために、また論理型プログラミングでは単一化処理の際に使用されます。

等価性には複数の有効な定義があり、特定の言語は様々な設計上の側面に応じて、それらの1つ、あるいは複数の定義を採用する可能性があります。等価性の一つの意味は、「a がbと等しい場合、ab はどのような文脈においても違いを意識することなく互換的に使用できる」というものです。しかし、この記述は必ずしも当てはまりません。特に、可変性と内容の等価性の両方を考慮すると、この記述は当てはまりません。

場所の平等性とコンテンツの平等性

特にオブジェクト指向プログラミングにおいては、比較によってデータ型継承等価性同一性といった問題が生じることがあります。多くの場合、以下の点を区別する必要があります。

  • 同じ種類の2つの異なる物体、例:2つの手
  • 2つの物体は等しいが異なるものである。例:2枚の10ドル紙幣
  • 2つの物体は等しいが異なる表現を持つ。例:1ドル紙幣と1ドル硬貨
  • 同じオブジェクトに対する2つの異なる参照(例:同じ人物に対する2つのニックネーム)

多くの現代のプログラミング言語では、オブジェクトやデータ構造は参照を介してアクセスされます。このような言語では、2種類の等価性をテストする必要があります。

  • 位置の等価性(同一性): 2つの参照(AとB)が同じオブジェクトを参照している場合。Aを介したオブジェクトとのやり取りは、Bを介した同じやり取りと区別がつかず、特にAを介したオブジェクトへの変更はBにも反映されます。
  • 内容の等価性: 2 つの参照 (A と B) によって参照されるオブジェクトが何らかの意味で同等である場合:
  • 構造的等価性(つまり、内容が同じであること)。これは、浅い(直下のサブパーツのみをテストする)または深い(サブパーツの等価性を再帰的にテストする)のいずれかです。これを実現する簡単な方法は、表現的等価性、つまり値が同じ表現を持つかどうかを確認することです。
  • 外部的な振る舞いを維持する、その他のカスタマイズされた等式。例えば、1/2 と 2/4 は有理数として見れば等しいとみなされます。考えられる要件としては、反射性対称性推移性に加えて、「オブジェクト A と B に対するすべての演算が同じ結果になる場合にのみ、A = B となる」というものがあります。

通常、最初のタイプの等価性は2番目のタイプの等価性を意味します(非数NaN)のように、それ自体と等しくないものを除く)。しかし、逆は必ずしも真ではありません。例えば、2つの文字列オブジェクトは、異なるオブジェクト(最初の意味では等しくない)であるにもかかわらず、同じ文字列(2番目の意味では等しい)を含む場合があります。この問題の詳細については、 同一性を参照してください。

多くの単純な分数を含む実数は、浮動小数点演算では正確に表現できないため、与えられた許容範囲内で等価性をテストする必要がある場合があります。しかし、そのような許容範囲は、推移性などの望ましい特性を容易に破る可能性があり、反射性も破る場合があります。IEEE浮動小数点標準では、NaN ≠ NaNが成立することを要求しています。対照的に、正値演算(正値支持者はIEEE浮動小数点数を置き換えることを意図しています)の(2022)プライベート標準は、同様の概念であるNaR(Not a Real)が採用されており、NaR = NaRが成立します。[ 1 ]

計算可能関数などの他のプログラミング要素は、等価性の概念を持たないか、あるいは計算不可能な等価性しか持たない場合があります。こうした理由から、一部の言語では、基底クラス、インターフェース、特性、またはプロトコルといった形で「比較可能」という概念を明示的に定義しています。これらの概念は、ソースコード内で宣言することによって明示的に使用されるか、または関連する型の構造を通じて暗黙的に使用されます。

異なる型の値の比較

JavaScriptPHPVBScript、その他いくつかの動的型付け言語では、標準の等価演算子はいわゆる緩い型付けに従います。つまり、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つのデータ項目(例えばab )の比較結果に数値を関連付けたい場合、通常の慣例では、 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(すべて真またはすべて偽)を持ちます。

E{×<yy>××yy×{\displaystyle E={\begin{cases}x<y\\y>x\\x\ngeq y\\y\nleq x\end{cases}}}

これは、ドメインが適切に順序付けられていることに依存します。

標準的な関係演算子

プログラミング言語で最も一般的に使用される数値関係演算子を以下に示します。標準SQLではBASICと同じ演算子が使用されますが、多くのデータベースでは標準の演算子!=に加えて、以下の演算子も使用できます。SQLは厳密なブール代数に準拠しており、以下のほとんどの言語で一般的に使用される短絡評価は使用しません。例えばPHPは短絡評価を使用しますが、それ以外は多くのSQLデータベースと同様に、これら2つの演算子がエイリアスとして定義されています。 <>

一般的な関係演算子
大会 等しい等しくないより大きい未満より大きいか等しい以下​
印刷中 > <
FORTRAN [注 1 ].EQ..NE..GT..LT..GE..LE.
ALGOL 68 [注 2 ]=><
/=>=<=
eqnegtltgele
APL=><
BASICMLPascal [注 3 ]=<>[注4 ]><>=<=
Cのような[注5 ]==!=><>=<=
おたふく風邪='=><'<'>
ルア==~=><>=<=
アーラン==/=><>==<
=:==/=
ボーン型シェル[注6 ]-eq-ne-gt-lt-ge-le
バッチファイルEQUNEQGTRLSSGEQLEQ
ooRexxREXX=¬=><>=<=
\=
<>
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]
  1. ^ FORTRAN II、III、IV、66、77 を含む。
  2. ^ ALGOL 68 :ストロッピング方式は、文字セットが制限されているプラ​​ットフォーム (の代わり>=にまたはGEを使用するなど)、強調のないプラットフォーム( を使用する)、または大文字のみのプラットフォーム(または を使用する) のコードで使用されます。bold'ge'.GE'GE'
  3. ^ ALGOL Simula Modula-2 Eiffel SQLスプレッドシートの数式などを含みます
  4. ^ Modula-2は以下も認識します#
  5. ^ C C++ C# Go Java JavaScript Perl (数値比較のみ)、 PHP Python Ruby Rを含みます。
  6. ^ Bourne Shell Bash KornShell Windows PowerShell を含みます。記号「 」とは通常、シェル内でリダイレクトに使用されるため、他の記号を使用する必要があります。ハイフンなしの「 」は、 Perlで文字列比較に使用されます<>
  7. ^ MATLABは、他の点ではCと同様の構文を使用していますが、を使用しません。MATLABでは、以下のテキストをコマンドラインとしてオペレーティングシステムに送信します。最初の形式は、等号を除いてSmalltalkでも使用されます。!=!=
  8. ^ FORTRAN 95、2003、2008、2015 を含む。

その他の慣習はあまり一般的ではありません。Common LispMacsyma / 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) が:=割り当て用に導入され、標準が=同等に利用可能になりました。この規則には、CPLALGOL WALGOL 68、 Basic Combined Programming Language ( BCPL )、Simula、 SET Language ( SETL )、PascalSmalltalkModula-2AdaStandard MLOCamlEiffelObject Pascal ( Delphi )、OberonDylan、 VHSIC ハードウェア記述言語 ( VHDL )、およびその他のいくつかの言語が従っています。

BとC

ほとんどのプログラミング言語におけるこの統一された事実上の標準は、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 ); }

JavaC#にはCと同じ演算子がありますが、これらの言語ではこの誤りは通常コンパイルエラーを引き起こします。これは、if条件式は 型である必要があり、他の型(例えば数値)を 型にboolean変換する暗黙的な方法がないためです。したがって、 に代入される変数が 型(またはラッパー型)でない限り、コンパイルエラーが発生します。 booleanbooleanBoolean

Pascal、Delphi、AdaなどのALGOL系言語(ネストされた関数定義が可能な点)、Python、そして多くの関数型言語などでは、代入演算子は(節を含む)に出現できないため、この種のエラーは発生しません。GNUコンパイラコレクションif(GCC)などの一部のコンパイラは、if文内に代入演算子を含むコードをコンパイルする際に警告を発しますが、if条件式内で代入演算子を使用する正当な方法もいくつかあります。そのような場合、警告を回避するには、代入演算子を明示的に括弧で囲む必要があります。

同様に、 BASICなどの一部の言語では、代入=等価性は構文的に分離されているため、代入と等価性の両方に記号のみを使用します(Pascal、Ada、Python などでは、代入演算子は式に出現できません)。

プログラマーの中には、定数との比較を通常の順序とは逆に記述する習慣を持つ人がいます。

// = と == の誤った使用はコンパイル時エラーになりますif ( 2 == a ) { // ... }

を誤って使用した場合=、2は変数ではないため、結果として得られるコードは無効になります。コンパイラはエラーメッセージを生成し、適切な演算子に置き換えることができます。このコーディングスタイルは、左手比較、またはヨーダ条件と呼ばれます。

この表には、さまざまな言語でこれら 2 種類の等価性をテストするためのさまざまなメカニズムがリストされています。

言語身体的平等構造的平等注記
アルゴル68a :=: bまたはa is ba = baと がbポインタである 場合
CC++a == b*a == *baと がbポインタである 場合
C#object.ReferenceEquals(a, b)a.Equals(b)演算子==はデフォルトで になりますが、代わりにを実行するようにオーバーロードReferenceEqualsできます。 Equals
コモンリスプ(eq a b)(equal a b)
アーランa =:= ba == baとbが数値の場合
フォートランassociated (pa, b)a == bpaはポインタです
行くa == breflect.DeepEqual(*a, *b)aとbがポインタの場合
ジャワa == ba.equals(b)
JavaScripta === ba == ba と b が同等の文字を含む 2 つの文字列オブジェクトの場合でも、=== 演算子は true を返します。
OCamlSmalltalka == ba = b
パスカルa^ = b^a = b
パール$a == $b$$a == $$b$aと が$bスカラーへの参照である 場合
PHP$a === $b$a == $b$aと が$bオブジェクトである 場合
パイソンa is ba == b
ルビーa.equal?(b)a == b
スキーム(eq? a b)(equal? a b)
迅速a === ba == baとbがクラス型を持つ場合
Visual Basic .NET [不等式 1 ]a Is bまたはobject.ReferenceEquals(a, b)a = bまたはa.Equals(b)C#と同じ
Objective-C ( CocoaGNUstep )a == b[a isEqual:b]と はabインスタンスであるオブジェクトへのポインタです。NSObject
  1. ^特許出願:2003年5月14日、マイクロソフトの従業員がオペレータに関する特許出願(米国特許出願番号20,040,230,959 「IS NOT OPERATOR」)を出願しました。この特許は2004年11月18日に付与されました。ISNOT

Ruby では、 はa === b「b はセット a のメンバーである」という意味で使用されますが、メンバーであることの意味の詳細は、関係するデータ型によって大きく異なります。===は、ここでは「case 等価」または「case 包含」演算子として知られています。

参照

注釈と参考文献

  1. ^正算術の標準(2022)
  2. ^否定、ドヴァン。「すごい」GitHub。2024 年7 月 25 日に取得
  3. ^ 「オブジェクトの比較」 . PHPマニュアル. PHPグループ. 2014年6月29日閲覧
  4. ^ 「PHP: 比較演算子 - マニュアル」 。 2008年7月31日閲覧
  5. ^ Mathematica関係演算子と論理演算子
  6. ^ 「なぜ等価性を比較する方法がこんなにたくさんあるのでしょうか?」 Stack Overflow 。 2024年7月25日閲覧
  7. ^ Alexandrescu, Andrei (2010). 『Dプログラミング言語』. Addison Wesley. p. 58. ISBN 978-0-321-63536-5
  8. ^ ALGOL系言語だけでなくFORTRANやBASICでも使用される
  9. ^一部のプログラマーは、これらの新しい記号の二重の意味(ビット演算子と論理接続詞)に混乱したため( Dennis Ritchieによると)、& と | のビット演算子の意味のみが保持されました。
  10. ^デニス・リッチーは、これは「型の経済性」と関係があるかもしれないと示唆している。これは、特定の種類のプログラムでは変数の更新が比較よりも頻繁に行われる可能性があるためである。
  11. ^ゼロのスカラー値は false として解釈され、ゼロ以外のスカラー値は true として解釈されます。これは通常、アセンブリ言語の慣用句と同様に、整数型で使用されます。
  12. ^ブライアン・カーニハン、デニス・リッチー (1988) [1978]. 『プログラミング言語C』(第2版). プレンティス・ホール.、19歳