関係演算子のソースを表示
←
関係演算子
ナビゲーションに移動
検索に移動
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループに属する利用者のみが実行できます:
登録利用者
。
このページのソースの閲覧やコピーができます。
[[計算機科学]]において、'''関係演算子'''(かんけいえんざんし、{{lang-en-short|relational operator}})または'''比較演算子'''(ひかくえんざんし、{{lang-en-short|comparison operator}})とは、[[プログラミング言語]]の[[演算子 (コンピュータ言語)|演算子]]で、2つの対象の[[二項関係|関係]]を調べるものをいう。たとえば、[[同値関係]]を調べる[[等号]](<math>5 = 5</math> の <math>=</math>)や、[[順序集合|順序関係]]を調べる[[不等号]](<math>4 > 3</math> の <math>></math>)などが含まれる。 [[Java]]や[[C Sharp|C#]]など、独立した[[ブーリアン型]]を[[型システム]]に持つ言語では、関係演算子は2つの[[被演算子|オペランド]]の間に演算子が表す関係が成り立つかどうかによって真 (true) または偽 (false) を返す。一方で、[[C言語]]などのブーリアン型を持たない初期の言語では、関係演算子は整数 0(偽を意味する)または 1(真を意味する)を返す。 関係演算子を含む[[式 (プログラミング)|式]]は、'''関係式''' ({{lang|en|relational expression}}) または'''条件''' ({{lang|en|condition}}) と呼ばれる。また、技術的な文献において、関係を言葉で説明する代わりに関係演算子が用いられることもある。多くのプログラミング言語では、関係演算子は[[中置記法]]で記述される。たとえば、以下のC言語のコードは、''x'' が ''y'' より小さい場合にメッセージを表示するものである。 <syntaxhighlight lang="c"> if (x < y) { printf("x is less than y in this example\n"); } </syntaxhighlight> 他方で[[ポーランド記法|前置記法]]を採用している言語もある。たとえば、[[LISP|Lisp]]では以下のように書く。しかしこれは演算子というよりも、Lispでは[[識別子]]に使える文字の範囲が緩くて、単に <code>>=</code> という名前の関数であるというだけである。 <syntaxhighlight lang="lisp"> (if (>= x y) (display "x is greater than or equal to y in this example")) </syntaxhighlight> == 標準的な関係演算子 == 多くのプログラミング言語で使用されている標準的な数値比較演算子を以下に示す。 {| class="wikitable" style="text-align: center;" |+ 一般的な数値比較演算子 ! 様式 ! 等しい ! 等しくない ! より大きい ! より小さい ! 以上 ! 以下 |- ! 数学 | <math>=</math> | <math>\ne</math> | <math>></math> | <math><</math> | <math>\ge</math> | <math>\le</math> |- ! rowspan="1" | [[FORTRAN|Fortran]]<ref group="note">Fortran 90からはC言語ライクな比較演算子もサポートされている。</ref> | <code>.EQ.</code> | <code>.NE.</code> | <code>.GT.</code> | <code>.LT.</code> | <code>.GE.</code> | <code>.LE.</code> |- ! rowspan=3 | [[ALGOL 68]]<ref group="note">[[ALGOL 68]]: "[[Stropping (syntax)|stropping]]" regimes are used in code on platforms with limited character sets (e.g. use <code>>=</code> or <code>GE</code> instead of <code>≥</code>), platforms with no <code>'''bold'''</code> [[Emphasis (typography)|emphasis]] (use <code>'ge'</code>), or platforms with only [[UPPERCASE]] (use <code>.GE</code> ''or'' <code>'GE'</code>).</ref> | rowspan=2 | <code>=</code> | <code>≠</code> | rowspan=2 | <code>></code> | rowspan=2 | <code><</code> | <code>≥</code> | <code>≤</code> |- | <code>/=</code> | <code>>=</code> | <code><=</code> |- | <code>'''eq'''</code> | <code>'''ne'''</code> | <code>'''gt'''</code> | <code>'''lt'''</code> | <code>'''ge'''</code> | <code>'''le'''</code> |- ! [[BASIC]]ライク<ref group="note">[[Visual Basic]]、[[Microsoft Visual Basic .NET|VB.NET]]、[[OCaml]]、[[SQL]]、[[Standard ML]]など。</ref> | <code>=</code> | <code><></code> | <code>></code> | <code><</code> | <code>>=</code> | <code><=</code> |- ! [[MUMPS]] | <code>=</code> | <code>'=</code> | <code>></code> | <code><</code> | <code>'<</code> | <code>'></code> |- ! [[Pascal]]ライク<ref group="note">[[Simula]]、[[Modula-2]]、[[Object Pascal]]、[[Delphi]]、[[Ada]]、[[Oberon]]、[[OCaml]]、[[Standard ML]]など。</ref> | <code>=</code> | <code><></code> | <code>></code> | <code><</code> | <code>>=</code> | <code><=</code> |- ! C言語ライク<ref group="note">C、[[C++]]、[[C Sharp|C#]]、[[Go (プログラミング言語)|Go]]、[[Java]]、[[JavaScript]]、[[Perl]](文字列比較演算子は別に用意されている)、[[PHP (プログラミング言語)|PHP]]、[[Python]]、[[Ruby]]、[[R言語|R]]など。</ref> | <code>==</code> | <code>!=</code> | <code>></code> | <code><</code> | <code>>=</code> | <code><=</code> |- ! rowspan="2" |[[Bourne Shell|sh]]後継の[[シェル]]<ref group="note">[[bash]]、[[KornShell|ksh]]、[[Z_Shell|zsh]]など。上段のC言語ライクの演算子はシェルでは算術式評価の文脈でのみ数値比較の意味を持つ。それ以外の文脈では上段は文字列比較演算子である(文脈によっては<code><</code>等にクォートが必要)ため、その文脈で数値比較を行うには下段の演算子を使う。</ref> | <code>==</code> | <code>!=</code> | <code>></code> | <code><</code> | <code>>=</code> | <code><=</code> |- | <code>-eq</code> | <code>-ne</code> | <code>-gt</code> | <code>-lt</code> | <code>-ge</code> | <code>-le</code> |- ! [[バッチファイル]] | <code>EQU</code> | <code>NEQ</code> | <code>GTR</code> | <code>LSS</code> | <code>GEQ</code> | <code>LEQ</code> |- ! rowspan="2" |[[MATLAB]]<ref group="note">MATLABはC言語ライクな比較演算子を提供するが、<code>!=</code> を用いない。MATLABにおいて、<code>!</code> は<!-- 以降のテキストをコマンド行として[[オペレーティングシステム]]に送る働きをするからである。 --><!-- コマンドシェル(Unixならば /bin/sh )に送るのであってOSに送るのではない。 -->シェルコマンドの記述に用いられるからである。上段の形式は[[Smalltalk]]でも用いられるが、等号は <code>=</code> となる。</ref> | <code>==</code> | <code>~=</code> | <code>></code> | <code><</code> | <code>>=</code> | <code><=</code> |- | <code>eq(x,y)</code> | <code>ne(x,y)</code> | <code>gt(x,y)</code> | <code>lt(x,y)</code> | <code>ge(x,y)</code> | <code>le(x,y)</code> |- ! rowspan="2" |[[Mathematica]]<ref>[http://reference.wolfram.com/mathematica/tutorial/RelationalAndLogicalOperators.ja.html 関係演算子と論理演算子—Wolfram Mathematica 9 ドキュメント]</ref> | <code>==</code> | <code>!=</code> | <code>></code> | <code><</code> | <code>>=</code> | <code><=</code> |- | <code>Equal[x,y]</code> | <code>Unequal[x,y]</code> | <code>Greater[x,y]</code> | <code>Less[x,y]</code> | <code>GreaterEqual[x,y]</code> | <code>LessEqual[x,y]</code> |} {{reflist|group="note"}} == 等号 == === 代入演算子との混乱 === C言語から直接または間接的に派生したプログラミング言語では、同値関係の関係演算子として、直感的な <code>=</code> ではなく <code>==</code> を用いる。一方、<code>=</code> を用いる言語としては Pascal、BASIC、Ada、Standard ML、Objective Caml、SQL、VHDL などがある。 C言語は広範囲に普及したため、後発のプログラミング言語における構文や仕様はC言語のそれを参考に定義されたものも多いが、そのうちの一つがこの <code>==</code> 演算子である。この独特の構文は、[[B言語]]開発の初期の段階で <code>=</code> を別の意味に割り当てたことに端を発する。ALGOLとFORTRANの流れを汲むB言語の設計者は、タイピングを減らしたいという要望から、頻繁に記述される更新・[[変数 (プログラミング)#代入|代入]]操作のためのコピー演算子として <code>=</code> を代用することを決定した(これは <code>A = A + 1</code> のような、一見して「数学的には不成立」な式が許容されることを意味する)。代わりに、<code>=</code> が本来担う役割である等号として <code>==</code> が使われることとなった。C言語はこれらの演算子をそのまま引き継ぎ、以後JavaやC#をはじめとする多くの言語がこの構文を採用したのである。 これらのC言語ファミリーにおける <code>=</code> の用法は[[バグ]]の温床になりうる。C言語にはブーリアン型がなく、[[if文]]や[[while文]]の条件式には真偽値に評価されうる任意の数値型の式を受け付ける(ゼロあるいはゼロ相当を偽、非ゼロを真とする)。またC言語における代入は[[文 (プログラミング)|文]]ではなく[[式 (プログラミング)|式]]であり値を持つ。そのため、プログラマーが <code>if (x == y)</code> の代わりに、<code>if (x = y)</code> とミスタイプしても構文的には合法となってしまうのである。C言語において、<code>if (x == y)</code> は大雑把に言えば「''x'' と ''y'' が等しければ後続の文を実行せよ」を意味する。しかし、<code>if (x = y)</code> とミスタイプすると「''x'' に ''y'' の値を割り当て、もし ''x'' の新しい値が0でなければ、後続の文を実行せよ」という意味になってしまう。たとえば、下記の例で <code>if (x = y)</code> と書いてしまうと、''y'' が ''x'' に代入され両方とも2になり、更に ''x'' の値2は0ではないので、常に if 文のブロックが実行される。したがって、以下のコードは "x is 2 and y is 2" を出力する<ref name="kandr">{{cite book|title=The C Programming Language|last=Kernighan|first=Brian|coauthors=Dennis Ritchie|publisher=Prentice Hall|origyear=1978|year=1988| edition=Second edition}}, 19</ref>。 <syntaxhighlight lang="c"> int x = 1; int y = 2; if (x = y) { /* yが0でなければ以下のコードは常に実行される */ printf("x is %d and y is %d\n", x, y); } </syntaxhighlight> 他の言語やコンパイラの中には、このようなミスを事前に防ぐように工夫されているものもある。 * 同じ演算子を持つJavaやC#も同様の問題を孕んでいるが、これらの言語ではこの種の誤りは、ほとんどの場合コンパイルエラーとして検出できる。[[if文]]や[[while文]]などの条件式はブーリアン型に制約され、また他の型(例えば整数型)からブーリアン型に暗黙的に変換されることもほとんどないからである{{efn|ただしJavaの{{Javadoc:SE|name=java.lang.Boolean|java/lang|Boolean}}は<code>boolean</code>に暗黙変換される。また、C#では<code>bool</code>への暗黙変換演算子や、<code>true</code>/<code>false</code>演算子をユーザー定義することもできる。このようなケースでは、JavaやC#であっても条件式を書くべきところに間違って代入式を書けてしまう。}}。 * [[GNUコンパイラコレクション|GCC]]/[[Clang]]や[[Microsoft Visual C++]]などのいくつかのコンパイラでは、if や while の条件式中に代入演算子を含んでいるコードをコンパイルするときに警告を出す(<code>-Wparentheses</code>、C4706<ref>[https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-4-c4706 Compiler Warning (level 4) C4706 | Microsoft Learn]</ref>)。 * PascalやAdaなどでは、Cと違い代入演算子は<code>:=</code>、等値比較演算子は<code>=</code>であり<ref>[https://www.adaic.org/learn/materials/intro/part3/ Intro to Ada Pt. 3 - Ada Resource Association]</ref>、また式の途中に代入演算子は登場できないので、この種の誤りは排除できる。 * Pythonにおいては、C同様に代入演算子は<code>=</code>、等値比較演算子は<code>==</code>であるものの、代入は式ではなく文であり<ref>[https://docs.python.org/3/reference/simple_stmts.html#assignment-statements 7. Simple statements — Python 3.11.5 documentation]</ref>、この種の誤りは排除できる。Python 3.8では値を返す代入式が導入されたが、Pascalと類似の代入演算子<code>:=</code>が使われるため、通常は比較演算子の<code>==</code>と混同するようなことはない<ref>[https://docs.python.org/3/reference/expressions.html#assignment-expressions 6. Expressions — Python 3.11.5 documentation]</ref>。 * BASICなどのいくつかの言語では、文脈に応じて構文的に弁別できることから、代入演算子<ref>[https://learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/operators/assignment-operator = Operator - Visual Basic | Microsoft Learn]</ref>と等値比較演算子<ref>[https://learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/operators/comparison-operators Comparison Operators in Visual Basic | Microsoft Learn]</ref>の両方に <code>=</code> 記号を使用する。BASIC系では代入は式ではなく文であり<ref>[https://learn.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/statements#assignment-statements Statements in Visual Basic | Microsoft Learn]</ref>、代入演算子としての<code>=</code>のほうは式中に出現することがない。 また、プログラマーの中には予防策として、定数に対する比較を記述するとき、以下のように直感とは逆の順でオペランドを記述する者もいる。定数は左辺値ではないので、このように比較演算子の左側に記述するスタイルにしておけば、たとえ誤って <code>=</code> と書いてしまったとしても、そのコードは不適格となる。コンパイラは不適格コードに対してエラーメッセージを出力し、コンパイルを中断するので、記述ミスに気づくことができ、結果、適切な演算子に修正できるのである。このコーディングスタイルは[[ヨーダ記法]]や left-hand comparison として知られている。ただしこの記法には、比較対象の少なくとも片方が左辺値を持たないような場合にしか使えない、多くの場合は重要な側(自然言語で考えたときに主語となる側)の式が後から現れることになる、といった欠点がある。コーディング規約として推奨しているプロジェクトもあれば、推奨していないプロジェクトもある。 <syntaxhighlight lang="c"> if (2 == a) { /* 仮に = と == を誤用した場合はコンパイルエラーを引き起こす */ /* ... */ } </syntaxhighlight> なお、C/C++では、以下のように意図的に条件式中に代入式が書かれることもある。ただし前述のように、コンパイラは通例このようなコードに対しても警告を出す。 <syntaxhighlight lang="c"> FILE* fp = NULL; if (fp = fopen("sample.txt", "r")) { /* 指定したファイルを開くことができ、fp が non-null となった場合の処理 */ fclose(fp); fp = NULL; } </syntaxhighlight> ==== PHP での拡張 ==== PHPでは、<code>==</code> 演算子をさらに拡張し、型が異なっても値が等しければ真を返す <code>==</code> 演算子(たとえば <code>4 == "4"</code> は真である)と、値が等しくかつ同じ型を持っている場合に真を返す <code>===</code> 演算子(たとえば <code>4 === 4</code> は真であるが <code>4 === "4"</code> は偽である)の2種類の演算子を持っている<ref name="php">{{cite web|url=http://php.net/manual/en/language.operators.comparison.php|title=PHP: Comparison Operators - Manual|accessdate=2008-07-31}}</ref>。<code>x == 0</code> は ''x'' が <code>0</code>、<code>"0"</code>(文字 0 を含む文字列)または <code>false</code>(PHPでは他の言語でも見られるように、<code>false</code> は <code>0</code> と等しい)のときに真を返す。これは、変数に 0 の値が割り当てられているかを確認するのに便利であるが、必ずしも期待される動作とは限らない<ref name="php" />。一方で、<code>x === 0</code> は ''x'' が <code>0</code> のときのみ真を返す。 === オブジェクトの同一性と内容の等価性 === 多くの現代的なプログラミング言語において、オブジェクトやデータ構造は[[参照 (計算機科学)|参照]]を通じてアクセスされる。そのような言語では、2種類の異なる等価性を判定する必要性が生じる: * 物理的な等価 - 2つの参照が同じオブジェクトを参照しているかどうか * 構造的な等価 - 2つの参照が参照するオブジェクトがある意味において(たとえば内容が同じであるなど)等しいかどうか **浅い等価判定(対象オブジェクトの持つ各メンバについて等価性を判定する) **深い等価判定(対象オブジェクトの持つ各メンバに加えて、対象オブジェクトから参照できる全てのオブジェクト各メンバについても等価性を判定する) 通常、前者の等価性は後者の等価性を含意しているが(自身に等しくないような [[NaN]] のようなものは除く)、逆は必ずしも真ではない。たとえば、2つの[[文字列]]オブジェクトは別個のオブジェクトであるかもしれない(前者の意味では等しくない)が、同じ文字の並びを持ちうる(後者の意味で等しい)。 次の表では、これらの2種類の等価性を判定するための異なる方法を、様々な言語において一覧できるようにしてある。 {| class="wikitable" ! 言語 !! 物理的な等価 !! 構造的な等価 !! 備考 |- | C, C++ || <code>a == b</code> || <code>*a == *b</code> || <code>a</code>と<code>b</code>はポインタである |- | C# || <code>object.ReferenceEquals(a, b)</code><sup>1</sup> || <code>a.Equals(b)</code><sup>1</sup> || |- | [[Common Lisp]] || <code>(eq a b)</code> || <code>(equal a b)</code> || |- | Java || <code>a == b</code> || <code>a.equals(b)</code> || <code>a</code>と<code>b</code>は参照である |- | OCaml || <code>a == b</code> || <code>a = b</code> || |- | Pascal || <code>a^ = b^</code> ||<code>a = b</code> || |- | Perl || <code>$a == $b</code> || <code>$$a == $$b</code> || <code>$a</code>と<code>$b</code>はスカラーリファレンスである |- | PHP5 || N/A || <code>$a == $b</code> || <code>$a</code>と<code>$b</code>はオブジェクトである |- | Python || <code>a is b</code> || <code>a == b</code> || |- | Ruby || <code>a.equal?(b)</code> || <code>a == b</code> || |- | [[Scheme]] || <code>(eq? a b)</code> || <code>(equal? a b)</code> || |- | VB.NET || <code>a Is b</code> || <code>a = b</code> || |- | [[Objective-C]] || <code>a == b</code> || <code>[a isEqual:b]</code> || <code>a</code>と<code>b</code>はオブジェクトへのポインタである |} : <sup>1</sup> C# では、参照型に対する <code>==</code> 演算子は既定で <code>ReferenceEquals()</code> メソッドの呼び出しと等価になるが、代わりに <code>Equals()</code> メソッドを実行するように[[演算子オーバーロード]]をすることができる。このことによって、構造的な等価性の方がより直感的と思われる型において、<code>==</code> で構造的な等価性を判定するようにできる。特に[[文字列]]比較において、このことが効果的である(Java で文字列比較は <code>a.equals(b)</code> と書かなければならないが、C# では <code>a == b</code> と書ける)。ただし、変更可能 (mutable) な参照型の場合は、<code>==</code>演算子をオーバーロードすべきではないとされている<ref>[https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/equality-operators Equality Operators - Framework Design Guidelines | Microsoft Learn]</ref>。多くの.NET言語では、参照型における組み込みの比較演算子は参照の等価性を判定するために用意されているものであり、[[驚き最小の原則]]の観点からも、一般的にオーバーロードは避けるべきとされている<ref>[https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1046 CA1046: Do not overload operator equals on reference types (code analysis) - .NET | Microsoft Learn]</ref>。 == 論理的同値性 == 一見して自明ではないが、比較演算子は、互いにほかの比較演算子を用いて論理的に同値な命題を構成できる。これは、ちょうど[[ブール論理]]の[[論理演算|論理演算子]] XOR、AND、OR、NOT の間で見られる関係に似ている。以下の4つの条件式は互いに[[同値|論理的同値]]である。 * <math>x < y</math> * <math>y > x</math> * <math>\neg (x \geq y)</math> * <math>\neg (y \leq x)</math> さらに、等号も不等号を用いて表現することができる。 * <math>x = y \Leftrightarrow \neg (x > y \vee y > x)</math> * <math>x = y \Leftrightarrow x \geq y \wedge y \geq x</math> この性質をプログラミングに応用して、不等号 ≥ だけ(または、≥ と = の二つだけ)を真面目に実装し、ほかの比較演算子を ≥(または、≥ と =)を用いて定義することも行われる。 == 脚注 == === 注釈 === {{notelist}} === 出典 === {{reflist}} == 関連項目 == * [[演算子 (コンピュータ言語)|演算子]] * [[二項演算]] * [[二項関係]] * [[等号]] * [[不等号]] * [[等価性]] {{DEFAULTSORT:かんけいえんさんし}} [[Category:プログラミング言語の演算子]] [[Category:同値 (数学)]] [[Category:比較 (数学)]]
このページで使用されているテンプレート:
テンプレート:Cite book
(
ソースを閲覧
)
テンプレート:Cite web
(
ソースを閲覧
)
テンプレート:Efn
(
ソースを閲覧
)
テンプレート:Lang
(
ソースを閲覧
)
テンプレート:Lang-en-short
(
ソースを閲覧
)
テンプレート:Notelist
(
ソースを閲覧
)
テンプレート:Reflist
(
ソースを閲覧
)
関係演算子
に戻る。
ナビゲーション メニュー
個人用ツール
ログイン
名前空間
ページ
議論
日本語
表示
閲覧
ソースを閲覧
履歴表示
その他
検索
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
特別ページ
ツール
リンク元
関連ページの更新状況
ページ情報