後置インクリメント同士の比較演算で悩んでいます

解決済

回答 4

投稿

  • 評価
  • クリップ 0
  • VIEW 536

mer0

score 7

以下、2つのプログラムのうち、
例1)の結果がtrueになるのは理解できるのですが、
例2)の結果がfalseになるのが理解できません。。。。

例1)trueの場合
int i = 10;
boolean bo = (i++ == 10);
System.out.println("結果:" + bo);

結果:true

例2)falseの場合
int i = 10;
boolean bo = (i++ == i++);
System.out.println("結果:" + bo);

結果:false

当初、例2)のプログラムを作成した際は、
(i++ == i++)は、
インクリメントする前に演算が評価され、
そのあとにインクリメントされる想定でいました。

例2)のプログラムでは
どういった動きをするのかご教授お願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+5

Javaの場合限定、という前置きで。

Javaにおける前置インクリメント(++a)、後置インクリメント(a++)はどちらもです。
厳密には前者は単項演算子の式、後者は後置式と呼ばれます。
式というものは、評価されてを返します。変数の中身そのものではなく、我々には何等かの評価を行った後の値が見えます。

とっても古いですがJava言語規定というドキュメントがございまして、ここからそれぞれの式の仕様を引用します。

前置インクリメント演算子++では、

値1が変数の値に加えられ,合計は変数に格納される。
前置インクリメント式の値は,新しい値が格納された後の変数の値である。

とあります。
対して後置インクリメント演算子++では、

値1が変数の値に加えられ,合計は変数に格納される。
後置インクリメント式の値は,新しい値が格納される前の変数の値である。

と書かれています。
どちらも式を評価し、変数の中身が書き換わった後、評価結果として値を返しますが、前置のほうは新しく書き換わる前の値を返し、後置の場合は書き換わった後の値を返すという違いになります。

また、演算中における式は、カッコなどによる特別に順序の指定がなければ左から右へ順に評価されていきます。

なので、boolean bo = (i++ == i++);がどのように評価されるかというと、まずカッコの中身が優先なので(i++ == i++)が先に評価される。
わかりやすいように逆ポーランド記法風に書くと、i++ i++ == で、左から順に評価されていきます。
まず最初のi++が評価されます。元のiは10なので、まず変数が演算されiが11になり、式の評価結果としては変数変更前の10が返ります。
次に、真ん中のi++が評価されます。iの中身は11になっているので、変数が演算されると12になり、式の評価結果としては変更変更前の11が返ります。
最後に==演算子が評価されます。2項演算子なので直前2つの値が一致するか評価されます。直前2つの値は式の評価後、10 11となっているので一致せずfalseが返るというわけです。

このように、

  • 式とは何なのか
  • 評価と値の関係
  • 各式の評価順序
    を踏まえ、この件は未定義でも不定でもなく、規定の動作ということになります。
    インクリメントの動作は行単位ではないのですよ!

なお、以下のサンプルプログラムで、インクリメント式の値がどんな値を返すのか、可視化できます。
実行してみてください。

     public static void main(String []args){
         int a,b;

         a = 10;
         b = add(a++ , a++);
        System.out.println("a=" + a);
        System.out.println("b=" + b);

     }

     public static int add(int i1, int i2){
        System.out.println("i1=" + i1);
        System.out.println("i2=" + i2);
         return i1 + i2;
     }

/* 実行結果
i1=10
i2=11
a=12
b=21
*/

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/09/26 23:30

    ありがとうございます!!!!
    ものすごくわかりやすく説明頂いたおかげで、
    すぐ理解できました!

    単項演算子、後置式ともに
    すでに値を評価した上で、
    変更前の値を返すか、後の値を返すかの
    違いということだったんですね

    逆ポーランド記法風という書き方があることも、
    知れたので大変感謝です

    キャンセル

+5

未定義か?

Javaでは左から右へ順に評価することが保証されています。

15.7. Evaluation Order
The Java programming language guarantees that the operands of operators appear to be evaluated in a specific evaluation order, namely, from left to right.

引用元: Java Language Specification > Chapter 15. Expressions

本筋の回答

i++ == i++について、例えばiが0のとき、次のように評価されます。

  1. ==の左辺が評価され、評価値i(0)を返したあとインクリメントされiの値が1になる。
  2. ==の右辺が評価され、評価値i(1)を返したあとインクリメントされiの値が2になる。
  3. ==の両辺の評価値が比較される。
  4. 当然 0 と 1 は等しくないので、falseが返される。

実験

int i = 0;
int a, b;

System.out.println(
    (a = i++) == (b = i++)
);
System.out.println(a);
System.out.println(b);

実行結果 Wandbox

false
0
1

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

-6

こういうのは多くの言語で、未定義とか、不定とかです。
普通に考えられる実装では、片方のiの値を求めて、インクリメントし、次に、他方のiの値を求めて、インクリメントするという物です。つまり、1011なので不一致です。
両辺のiを求めてから、両辺ともインクリメントするような実装(この場合は真になる)も許容するために、どういう結果になるか分からないという言語仕様になっています。

「片方」「他方」という書き方をしましたが、二項演算子の左項と右項のどちらを先にに評価するかも、多くの言語では決まっていません。Javaがどうかは調べてませんが。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

-7

i++ == i++

残念ながら、この式の動作は未定義となります
何が起ころうが不思議はない、ということですね

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/09/26 21:55

    そうなんですか!?
    ご回答いただきありがとうございます!!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.21%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る