関係演算子

計算機科学において、関係演算子（かんけいえんざんし、relational operator）または比較演算子（ひかくえんざんし、comparison operator）とは、プログラミング言語の演算子で、2つの対象の関係を調べるものをいう。たとえば、同値関係を調べる等号（ 5 = 5 {\displaystyle 5=5} の = {\displaystyle =} ）や、順序関係を調べる不等号（ 4 > 3 {\displaystyle 4>3} の > {\displaystyle >} ）などが含まれる。 Java など独立したブーリアン型を型システムに持つ言語では、関係演算子は2つのオペランドの間に演算子が表す関係が成り立つかどうかによって真または偽を返す。一方で、C言語などの言語では、関係演算子は整数 0（偽を意味する）または 1（真を意味する）を返す。 関係演算子を含む式は、関係式 (relational expression) または条件 (condition) と呼ばれる。また、技術的な文献において、関係を言葉で説明する代わりに関係演算子が用いられることもある。多くのプログラミング言語では、関係演算子は中置記法で記述される。たとえば、以下のC言語のコードは、x が y より小さい場合にメッセージを表示するものである。 if (x < y) { printf("x is less than y in this example\n"); } 他方で前置記法を採用している言語もある。たとえば、Lispでは以下のように書く。しかしこれは演算子というよりも、Lispでは識別子に使える文字の範囲が緩くて、単に >= という名前の関数であるというだけである。 (if (>= x y) (display "x is greater than or equal to y in this example")) 多くのプログラミング言語で使用されている標準的な数値比較演算子を以下に示す。 ^ Fortran 90からはC言語ライクな比較演算子もサポートされている。 ^ 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'). ^ VB.NET、OCaml、SQL、Standard MLなど。 ^ Simula、Modula-2、Delphi、Ada、Oberon、OCaml、Standard MLなど。 ^ C、C++、C#、Go、Java、JavaScript、Perl（文字列比較演算子は別に用意されている）、PHP、Python、Ruby、Rなど。 ^ sh、bash、ksh、Windows PowerShellなど。< と > はシェルではリダイレクトの記号として用いられるため別の記号を用いる必要がある。先頭のハイフンを除いたものはPerlでは文字列比較演算子として使用される。 ^ MATLABはC言語ライクな比較演算子を提供するが、!= を用いない。MATLABにおいて、! はシェルコマンドの記述に用いられるからである。上段の形式はSmalltalkでも用いられるが、等号は = となる。 C言語をはじめとする多くのプログラミング言語では、同値関係の関係演算子として、直感的な = ではなく == を用いる。（一方、= を用いる言語としては Pascal、Object Pascal、Ada、Standard ML、Objective Caml、SQL、VHDL などがある。） C言語の普及は広範囲に及んだため、ほかの多くのプログラミング言語はC言語の文法を参考にしたが、そのうちの一つがこの == 演算子である。この独特の構文は、B言語開発の初期の段階で = を別の意味に割り当てたことに端を発する。ALGOLとFORTRANの流れを汲むB言語の設計者は、タイピングを減らしたいという要望から、頻繁に記述される更新・代入操作のためのコピー演算子として = を代用することを決定したのである （これは A = A + 1 の様な一見して「不可能」な式が許容されることを意味する）。代わりに、= が本来担う役割である等号として == が使われることとなった。C言語はこれらの演算子をそのまま引き継ぎ、以後 Java、C# をはじめとする多くの言語がこの構文を採用したのである。 これらのC言語ファミリーにおける = の用法はバグの温床になりうる。プログラマーが if (x == y) の代わりに、if (x = y) とミスタイプすることがあるのである。C言語において、if (x == y) は大雑把に言えば「x と y が等しければ以下の文を実行せよ」を意味する。しかし、if (x = y) とミスタイプすると「x に y の値を割り当て、もし x の新しい値が0でなければ、以下の文を実行せよ」という意味になってしまう。たとえば、下記の例で if (x = y) と書いてしまうと、y が x に代入され両方とも2になり、更に x の値2は0ではないので、常に if 文のブロックが実行される。したがって、以下のコードは "x is 2 and y is 2" を出力する。 int x = 1; int y = 2; if (x = y) { /* yが0でなければ以下のコードは常に実行される */ printf("x is %d and y is %d\n", x, y); } 言語やコンパイラの中には、このようなミスを事前に防ぐように工夫されているものもある。 同じ演算子を持つ Java や C# も同じ問題を孕んでいるが、これらの言語ではこの誤りはコンパイルエラーとして検出できる。if の条件式はブーリアン型に制約を受け、またほかの型（例えば整数型）からブーリアン型に暗黙的に変換されることもないからである。 gccなどのいくつかのコンパイラでは、if の条件式中に代入演算子を含んでいるコード（意図的に書かれることもある）をコンパイルするときに警告を出す。 Ada と Python においては、（if 節も含めて）式の途中に代入演算子は登場できないので、この手の誤りは排除できる。 同様に BASIC などのいくつかの言語では、文法的に弁別できることから、代入と等式の両方に = 記号を使用する（Ada や Python と同様に、代入演算子は式中に出現することがない）。 また、プログラマーの中には予防策として、定数に対する比較を記述するとき、以下のように直感とは逆の順でオペランドを記述する者もいる。このようにしておけば、誤って = と書くと 2 は左辺値ではないので、書いたコードは不正になる。コンパイラはこれに対してエラーメッセージを出すので、結果、適切な演算子に修正できるのである。このコーディングスタイルは left-hand comparison として知られている。 if (2 == a) { /* = と == の誤用がコンパイルエラーを引き起こす */ /* ... */ } PHPでは、== 演算子をさらに拡張し、型が異なっても値が等しければ真を返す == 演算子（たとえば 4 == "4" は真である）と、値が等しくかつ同じ型を持っている場合に真を返す === 演算子（たとえば 4 === 4 は真であるが 4 === "4" は偽である）の2種類の演算子を持っている。x == 0 は x が 0、"0"（文字 0 を含む文字列）または false（PHPでは他の言語でも見られるように、false は 0 と等しい）のときに真を返す。これは、変数に 0 の値が割り当てられているかを確認するのに便利であるが、必ずしも期待される動作とは限らない。一方で、x === 0 は x が 0 のときのみ真を返す。 多くの現代的なプログラミング言語において、オブジェクトやデータ構造は参照を通じてアクセスされる。そのような言語では、2種類の異なる等価性を判定する必要性が生じる: 物理的な（浅い）等価 - 2つの参照が同じオブジェクトを参照しているかどうか 構造的な（深い）等価 - 2つの参照が参照するオブジェクトがある意味において（たとえば内容が同じであるなど）等しいかどうか 通常、前者の等価性は後者の等価性を含意しているが（自身に等しくないような NaN のようなものは除く）、逆は必ずしも真ではない。たとえば、2つの文字列オブジェクトは別個のオブジェクトであるかもしれない（前者の意味では等しくない）が、同じ文字の並びを持ちうる（後者の意味で等しい）。 次の表では、これらの2種類の等価性を判定するための異なる方法を、様々な言語において一覧できるようにしてある。 1 C# では、== 演算子はデフォルトで ReferenceEquals になるが、代わりに Equals を実行するように演算子オーバーロードをすることができる。このことによって、構造的な等価性の方がより直感的と思われる型において、== で構造的な等価性を判定するようにできる。特に文字列比較において、このことが効果的である（Java で文字列比較は a.equals(b) と書かなければならないが、C# では a == b と書ける）。 一見して自明ではないが、比較演算子は、互いにほかの比較演算子を用いて論理的に同値な命題を構成できる。これは、ちょうどブール論理の論理演算子 XOR、AND、OR、NOT の間で見られる関係に似ている。以下の4つの条件式は互いに論理的同値である。 x < y {\displaystyle x<y} y > x {\displaystyle y>x} ¬ ( x ≥ y ) {\displaystyle \neg (x\geq y)} ¬ ( y ≤ x ) {\displaystyle \neg (y\leq x)} さらに、等号も不等号を用いて表現することができる。 x = y ⇔ ¬ ( x > y ∨ y > x ) {\displaystyle x=y\Leftrightarrow \neg (x>y\vee y>x)} x = y ⇔ x ≥ y ∧ y ≥ x {\displaystyle x=y\Leftrightarrow x\geq y\wedge y\geq x} この性質をプログラミングに応用して、不等号 ≥ だけ（または、≥ と = の二つだけ）を真面目に実装し、ほかの比較演算子を ≥（または、≥ と =）を用いて定義することも行われる。 演算子 二項演算 二項関係 等号 不等号 等価性 ^ 関係演算子と論理演算子—Wolfram Mathematica 9 ドキュメント ^ Kernighan, Brian; Dennis Ritchie (1988) [1978]. The C Programming Language (Second edition ed.). Prentice Hall. , 19 ^ a b “PHP: Comparison Operators - Manual”. 2008年7月31日閲覧。