- PR -

演算子の優先順位について

投稿者投稿内容
Edosson
ぬし
会議室デビュー日: 2004/04/30
投稿数: 675
投稿日時: 2008-10-17 10:46
引用:

rainさんの書き込み (2008-10-17 10:27) より:

式の中に && があるため、先に && の左辺が評価されます。


この表現には抵抗があるなあ。
&&の方が、演算子として優先順位が高いように読めてしまう。
まあ、私も最初はここで引っかかったんですけど。

問題は、演算子そのものの優先順位と、それとは別の次元の優先順位の、
ふたつの優先順位が同時に存在してるってことですね。
rain
ぬし
会議室デビュー日: 2006/10/19
投稿数: 549
投稿日時: 2008-10-17 11:22
引用:

Edossonさんの書き込み (2008-10-17 10:46) より:
引用:

rainさんの書き込み (2008-10-17 10:27) より:

式の中に && があるため、先に && の左辺が評価されます。


この表現には抵抗があるなあ。
&&の方が、演算子として優先順位が高いように読めてしまう。
まあ、私も最初はここで引っかかったんですけど。

問題は、演算子そのものの優先順位と、それとは別の次元の優先順位の、
ふたつの優先順位が同時に存在してるってことですね。



別の次元の優先順位というのは、言語仕様でいうところの
引用:

15.7.2 Evaluate Operands before Operation
The Java programming language also guarantees that every operand of an operator (except the conditional operators &&, ||, and ? :) appears to be fully evaluated before any part of the operation itself is performed.


引用:

15.6.2演算前オペランド評価
Javaでは演算自身の実行前に,演算子のあらゆるオペランド(条件演算子&&, ||,そして? :を除く)が完全に評価されることを保証する。


のことですね。

a && b というのは、
コード:

if (a) {
return b;
} else {
return false;
}


を簡略化したもので、それゆえに conditional operators(条件演算子)と記述されているのかなぁ、と思いました。

----- 以下追記
三項演算子(? :)を使えばこう?
コード:

a && b → a ? b : a
a || b → a ? a : b



[ メッセージ編集済み 編集者: rain 編集日時 2008-10-17 11:26 ]

[ メッセージ編集済み 編集者: rain 編集日時 2008-10-17 11:26 ]
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2008-10-17 11:54
&&より|の方が優先順位が高いので
コード:

a && b | c



コード:

a && (b | c)


と解釈されます。
その上で、先頭から順に実行されaがfalseならば
ショートサーキットで(b | c)の評価をすることなくfalseと評価します。

仮に&&の方が優先順位が高いとすれば
コード:

(a && b) | c


と解釈され、aがfalseならばショートサーキットによりbを評価することなく
(a && b)がfalseと評価され、この結果とcと論理和を取ることになります。

[ メッセージ編集済み 編集者: nagise 編集日時 2008-10-17 11:55 ]
ぴあちゃん
ぬし
会議室デビュー日: 2008/02/07
投稿数: 287
投稿日時: 2008-10-17 12:14
コード:
(前置):a && b | c
    ↓
(後置):&& a | b c 



http://msdn.microsoft.com/ja-jp/library/aa711616(VS.71).aspx

1 && 1 => true
1 && 0 => false
0 && 1 => false
0 && 0 => false
第1項の評価が偽なら後続は無視されると。

true && false | doFunc()
なら、doFunc() が実行されるんですね。

boolean に "|" なんて使わないから 知らんかった。

おべんきょうさせてもらいました。



m.i
会議室デビュー日: 2008/10/06
投稿数: 9
投稿日時: 2008-10-17 14:00
Edossonさん、rainさん、スフレさん、ぴあちゃんさん、nagiseさん
ご指摘有難う御座いました。
また疑問に思っていた内容はまさにEdossonさんが指摘された、
引用:--------------------------------------------------
&&の方が、演算子として優先順位が高いように読めてしまう。
-------------------------------------------------------
の事です。

またこの問題が出ていた本にもnagiseさん指摘の通り
a && b | c

a && (b | c)
と解釈されるとの指摘がありました。
(ここまでは演算子の優先順位から考えて納得できました。)
さらにそうだとするならば&&よりも()の中を優先的に演算されるとも考えたのですが
なのになぜaが先に評価されるのか...?
という状態でした。

どうもすっきりしないのですが、Edossonさんご指摘の通り、
演算子そのものの優先順位と、それとは別の次元の優先順位の、
ふたつの優先順位が同時に存在するとの解釈しかないと考えております。

つまり、&&が出現した場合は演算子の優先順位以前に
&&の左側のオペランドが評価されその結果より(trueならば)&&より右の式が評価される。
このような感じでしょうか。
Edosson
ぬし
会議室デビュー日: 2004/04/30
投稿数: 675
投稿日時: 2008-10-17 14:46
必要な話は出尽くしてますが。

まずは、「|」と「||」、「&」と「&&」がどのように違うのか、確認してください。

本命は「|」と「&」であって、「||」と「&&」は脇役のはずなんですが、
脇役のはずの方が、プログラマ好みの動作だったりするんですよね。

引用:

m.iさんの書き込み (2008-10-17 14:00) より:

つまり、&&が出現した場合は演算子の優先順位以前に
&&の左側のオペランドが評価されその結果より(trueならば)&&より右の式が評価される。
このような感じでしょうか。



論理演算の場合、左項の値次第で、右項の評価がそもそも必要ない場合があるんですよ。
true、falseと、どの組み合わせの場合に必要なくなるのかは、自分で確認してください。
それをロコツにしたのが、ショートサーキット演算子です。

<追記>
オペランドの優先順位は、ちゃんと守られていますよ。

[ メッセージ編集済み 編集者: Edosson 編集日時 2008-10-17 14:49 ]
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2008-10-17 17:20
引用:

m.iさんの書き込み (2008-10-17 14:00) より:
つまり、&&が出現した場合は演算子の優先順位以前に
&&の左側のオペランドが評価されその結果より(trueならば)&&より右の式が評価される。
このような感じでしょうか。



演算子の優先順位というのは()をつける話。
評価の順番は前から。

と一口に言っても分かりにくいですね。
真面目に取り組むと構文解析木の話になっちゃうんですが、プログラムは
コード:
a && b | c


を以下のような木構造に解釈します。
コード:
&& ┬ a
   └ | ┬ b
        └ c


|の方が優先度が高いので (a && b) | c とはならず、a && (b | c)となっているのがわかるでしょうか。

こうした木構造を作ったのち、前から順に、つまり木の根元の上から順に処理が行われます。
まずは a と | のブロックの&&が行われるわけです。
aがfalseだとここでショートサーキットにより|部分は評価せずに飛ばされます。

演算子の優先順位というのは、この木構造を作る際にどの演算子が先に演算対象を取るかという話。
そして木構造が作られた後は、前から順に処理がされます。

人間だとここを一緒くたに行うので 2 + 3 * 4 のような場合は 3 * 4を行ってから2を足す、としているように思えるかもしれません。
でも実際には、まず暗黙に2+の部分を処理して「置いておく」ということをしているんですね。
その証拠に、0 * (4 * 5) を計算しろと言われたら、カッコの中を計算しないで0と答えるでしょう?
「0*を置いておく」とする変わりに「0を掛けるのでショートサーキットで0」としているわけです。
演算子の優先順位と演算順序は一致しないわけですね。

演算子で優先順位が一番高いのはカッコです。演算子の優先順位通りの順番で処理するのだとしたら
コード:
if (a != null && (a.hoge() || a.piyo())) {


というコードはNullPointerExceptionを発生することになります。
&&よりも演算順位の高いカッコ、つまりa.hoge() || a.piyo()を処理しなければなりません。
m.i
会議室デビュー日: 2008/10/06
投稿数: 9
投稿日時: 2008-10-17 17:50
Edossonさん、nagiseさん
更なるご指摘有難う御座います。
まさに私が混乱していた内容は、nagiseさんの指摘通りです。
引用----------------------
演算子の優先順位というのは、
この木構造を作る際にどの演算子が先に演算対象を取るかという話。
そして木構造が作られた後は、前から順に処理がされます。
---------------------------------------------------
まさにそういう事なのですね目から鱗です。
大変勉強になりました。

余談ですが、
このような知識はどこから取得されるのですか、javaの書籍は5〜6冊は読んでは
いるのですがこのような説明を見たことがありません。
お手間でなければで結構です。
ご意見頂けましたら幸いです。

スキルアップ/キャリアアップ(JOB@IT)