ビット演算子と論理演算子と真理値判定
初回公開:2017/09/03
最終更新:未
いろいろな言語を使っていると論理演算子とビット演算子がごちゃごちゃになってしまう。
論理演算とビット演算にはand,or,xor,&,|等の演算子があってどれがどれやら。
ここで、メジャーなスクリプト言語を中心に、ビット演算子と論理演算子について整理しておく事にする。
【 目次 】
ビット単位演算
ビット単位演算についてはPerl,Ruby,Python,PHPともにあまり差がないようなのでPythonのビット単位演算のドキュメントを以下に引用する。
ビット単位演算は、整数に対してのみ意味があります。負の数は、その 2 の補数の値として扱われます (演算中にオーバフローが起こらないように十分なビット数があるものと仮定します) 。
二項ビット単位演算の優先順位は全て、数値演算よりも低く、比較よりも高くなっています; 単項演算 ~ の優先順位は他の単項数値演算 (+ および -) と同じです。
以下の表では、ビット単位演算を優先順位が低い順に並べています:
演算 | 結果 | 注釈 |
---|---|---|
x ¦ y | x と y のビット単位 論理和 | |
x ^ y | x と y のビット単位 排他的論理和 | |
x & y | x と y のビット単位 論理積 | |
x << n | x の n ビット左シフト | (1)(2) |
x >> n | x の n ビット右シフト | (1)(3) |
~x | x のビット反転 |
注釈:
1.負値のシフト数は不正であり、 ValueError が送出されます。
2.n ビットの左シフトは、 pow(2, n) による乗算のオーバーフローチェックをしないものと等価です。
3.n ビットの右シフトは、 pow(2, n) による除算のオーバーフローチェックをしないものと等価です。
pythonのビット演算のコード
print(hex(0xf0 & 0x0f)) print(hex(0xf0 | 0x0f)) print(hex(0xf0 ^ 0x0f))
実行結果
0x0 0xff 0xff
2進,8進,16進のリテラル表記
c言語やPrelそしてPHPでは数値の先頭に0bや0O,oxを付ける事で、それぞれ2進数,8進数,16進数表記の数値を記述する事ができる。 0bや0oは大文字で0Bや0Oとしてもかまわない。
c言語,Perl,PHPのコード
printf("%d , %d , %d\n" , 0b1111,017,0xf); printf("%d , %d , %d\n" , 0B1111,017,0XF);
実行結果
15 , 15 , 15 15 , 15 , 15
RubyやPythonでは8進数を表すのに、先頭に0oを付ける。 2進数や16進数についてはCやPerlの表記方法と同じである。
rubyのコード
printf("%d , %d , %d\n" , 0b1111,017,0xf); printf("%d , %d , %d\n" , 0B1111,017,0XF);
pythonのコード
print(0b1111,0o17,0xf) print(0B1111,0O17,0XF)
そして、Rubyの場合には、10進数の表記に先頭に0dを付けて表す事もできる。
printf("%d , %d\n" ,0d15 ,0D15);
JavaやC#の最新バージョンではC言語と同じく数値の先頭に0bや0O,oxを付ける事で、それぞれ2進数,8進数,16進数表記ができる。
しかし、2進表記ができるようになったのは、Java7とC# 7からのようで、それ以前のバージョンでは2進数表記ができないようだ。
VisualStuidoのバージョンとC#の言語バージョンとNET Frameworkバージョンの関係については
まとめると、各言語とも先頭に0O,oxを付ける事により8進数,16進数のリテラル表記が可能。
2進数表記についてはRubyやPythonでは先頭に0bを、それ以外の言語では先頭に0を,oxを付ける事によりだいたいの言語でリテラル表記が可能。
真理値判定
c言語
多くのプログラミング言語の源流というべきc言語。
c言語では数値の0は偽,それ以外の数値は真と判定される。
そのため、長さ0の空文字""
も真と判定される。
NULLは0と定義されているため偽となる。
c言語のコード
if(""){ puts("True"); } else { puts("False"); } if(NULL){ puts("True"); } else { puts("False"); }
実行結果
True False
Perl
c言語と異なり、Perlでは空文字""や未定義値もFalseと判定される。
真偽値
数値 0, 文字列 '0' と "", 空リスト (), undef は全て真偽値 コンテキストでは偽となります。
その他の全ての値は真です。
真の値を ! や not で否定すると、特殊な偽の値を返します。
これを文字列として評価すると "" として扱われますが、数値として評価すると 0 として扱われます。
真または偽を返す、ほとんど Perl の演算子はこのように振る舞います。
Perlにおける真偽値を解説します。Perlにおける偽値は次の五つです。
1 undef 未定義値
2 "" 空文字列
3 0 0
4 "0" 文字列の0
5 () 空リスト
Perlにおける真値は上記以外すべてです。たとえば、"0.0"は、数値としては0と等しいが、真として扱われます。
%hash=( "undef" => undef, "空文字" => "0", "0" => 0 ); while (($key, $value) = (each %hash)){ print $key, " is " , $value ? "TRUE" : "FALSE", "\n"; } print "空リスト is " , () ? "TRUE" : "FALSE", "\n";
実行結果
空文字 is FALSE 0 is FALSE undef is FALSE 空リスト is FALSE
PerlにはTrue, Falseは定数定義されていないようで
しいて、TRUE, FALSEを定数定義すると、
use constant TRUE=> ! 0; use constant FALSE =>! TRUE; print "TRUE=「",TRUE, "」 , FALSE=「",FALSE, "」\n";
実行結果
TRUE=「1」 , FALSE=「」
このように定義した場合、TRUEは1 , FALSEは空文字に設定される。
Perlの流れを受け継ぐ(?)、Ruby,Pythonの場合は
Ruby
- 制御構造 (Ruby 2.0.0)
Ruby では false または nil だけが偽で、それ以外は 0 や空文 字列も含め全て真です。
true,falseについては
- Ruby プログラムの実行 (Ruby 2.0.0)
true
TrueClass の唯一のインスタンス true を返します。
false
FalseClass の唯一のインスタンス false を返します。
print "true=「",true, "」 , false=「",false, "」\n"; { "false" => false, "nil" => nil, "0" => 0, "空文字" => "" }.each{|key, value| print key, " is ",value ? "true" : "false", "\n" }
実行結果
true=「true」 , false=「false」 0 is true nil is false false is false 空文字 is true
Python
どのオブジェクトも真理値を判定でき、 if や while 条件に、または以下のブール演算の被演算子に使えます。以下の値は偽と見なされます:
- None
- False
- 数値型におけるゼロ。例えば 0, 0.0, 0j 。
- 空のシーケンス。例えば '', (), [] 。
- 空のマッピング。例えば {} 。
- ユーザ定義クラスのインスタンスで、そのクラスが bool() または len() メソッドを定義していれば、それらのメソッドが整数 0 または bool 値 False を返すとき。
それ以外の全ての値は真と見なされます — 従って、多くの型のオブジェクトは常に真です。
ブール値の結果を返す演算および組み込み関数は、特に注釈のない限り常に偽値として 0 または False を返し、真値として 1 または True を返します。 (重要な例外: ブール演算 or および and は常に被演算子のうちの一つを返します。)
PHP
boolean に変換する場合、次の値は FALSE とみなされます。
boolean の FALSE
integer の 0 (ゼロ)
float の 0.0 (ゼロ)
空の文字列、 および文字列の "0"
要素の数がゼロである 配列
特別な値 NULL (値がセットされていない変数を含む)
空のタグから作成された SimpleXML オブジェクト
その他の値は全て TRUE とみなされます (全ての resource および NAN を含みます)。
<?php $arr = array('boolean の FALSE' => FALSE, 'integer の 0 (ゼロ)' => 0, 'float の 0.0 (ゼロ)' => 0.0, '空の文字列' => "", '文字列の "0"' => "0",'空の配列' => array(),'特別な値 NULL' => NULL); foreach ($arr as $key => $value){ echo "$key is ",$value? "true\n" : "false\n"; }
実行結果
boolean の FALSE is false integer の 0 (ゼロ) is false float の 0.0 (ゼロ) is false 空の文字列 is false 文字列の "0" is false 空の配列 is false 特別な値 NULL is false
脈絡がないが、未定義値の値を指定した時のエラーが気になったので
TRUEとFALSEの値は?
- PHP: 定義済みの定数 - Manual
TRUE (boolean)
Booleans も参照ください。
FALSE (boolean)
Booleans も参照ください。
と記載されているが値が何かよくわからない。 以下のプログラムを実行してみると
echo "TRUE=「",TRUE,"」(",gettype(TRUE),")\n"; echo "FALSE=「",FALSE,"」(",gettype(FALSE),")\n";
実行結果
TRUE=「1」(boolean) FALSE=「」(boolean)
boolean型だけど値は、TRUEは数値の0,FALSEは空文字のようだ。
ブール演算(論理演算)
PerlとRUby
PerlとRubyの論理演算子にはand,or,notとC言語ふうの&&,||,!の両方が存在している。
ここで問題となるのがand,or,notと&&,||,~は全く同じなのかそれとも何か違いがあるのだろうか?
and,or,notと&&,||,!の違い演算子の優先順位にある。
以下、PerlとRubyの論理演算子に関するドキュメントを引用。
C スタイルの論理積 二項演算子の "&&" は、短絡の論理積演算を行ないます。 つまり、左被演算子が偽であれば、右被演算子は評価さえ 行なわれないということです。 評価される場合には、スカラーかリストかというコンテキストは、 右被演算子にも及びます。
C スタイルの論理和 二項演算子の "||" は、短絡の論理和演算を行ないます。 つまり、左被演算子が真であれば、右被演算子は評価さえ 行なわれないということです。 評価される場合には、スカラーかリストかというコンテキストは、 右被演算子にも及びます。
|| 演算子と && 演算子は、単に 0 や 1 を返すのではなく、最後に評価された値を 返すという点において、C と違っています。 これにより、かなり一般的に使えるホームディレクトリ ("0" でないとして) を 探す方法は:
$home = $ENV{'HOME'} || $ENV{'LOGDIR'} || (getpwuid($<))[7] || die "You're homeless!\n";
特に、これは代入のために二つの集合を選択するためには 使うべきではないことを意味します。
@a = @b || @c; # this is wrong @a = scalar(@b) || @c; # really meant this @a = @b ? @b : @c; # this works fine, though
Perl では、フロー制御に使う場合の多少読みやすい && と || の同義語として、 and 演算子と or 演算子が用意されています (下記参照)。 短絡の動作は全く同じです。 しかし、"and" と "or" の優先順位はかなり低くしてあるので、 引数に括弧を使っていないリスト演算子のあとに続けて使う場合にも、 安心して使うことができます:
unlink "alpha", "beta", "gamma" or gripe(), next LINE;
C スタイルの演算子では以下のように書く必要があります。
unlink("alpha", "beta", "gamma") || (gripe(), next LINE);
代入で "or" を使うと、したいことと違うことになります。 以下を参照して下さい。
...
論理積 二項演算子の "and" は両側の式の論理積を返します。 これは、優先順位がずっと低いことを除けば && と等価です。 つまり、これも短絡演算を行ない、右側の式は左側の式が 「真」であった場合にのみ評価されます。
論理和と排他論理和 二項演算子の "or" は両側の式の論理和を返します。 これは、優先順位がずっと低いことを除いて || と等価です。 これはフローを制御するのに有用です:
print FH $data or die "Can't write to FH: $!";
つまり、これも短絡演算を行ない、右側の式は左側の式が 「偽」であった場合にのみ評価されます。 優先度の関係で、これは代入には使わず、フローの制御のみに使うべきです。
$a = $b or $c; # bug: this is wrong ($a = $b) or $c; # really means this $a = $b || $c; # better written this way
しかし、代入がリストコンテキストの時に "||" をフロー制御に使おうとする場合、 代入により大きな優先順位を持たせるために "or" が必要かもしれません。
@info = stat($file) || die; # oops, scalar sense of stat! @info = stat($file) or die; # better, now @info gets its due
もちろん、常に括弧をつけてもよいです。
二項演算子の "xor" は両側の式の排他論理和を返します。 これはもちろん、短絡ではありません。
以下も参照
そして、Rubyは
プログラミングの利便のために一部のメソッド呼び出しと制御構造は演算子形 式をとります。Rubyには以下にあげる演算子があります。
高い :: [] +(単項) ! ~ ** -(単項) * / % + - << >> & | ^ > >= < <= <=> == === != =~ !~ && || .. ... ?:(条件演算子) =(+=, -= ... ) not 低い and or左の「高い」「低い」は演算子の優先順位です。 例えば「&&」は「||」より優先順位が高いので、以下のように 解釈されます。
…
and
例:
test && set
test and set
文法:
式 `&&' 式
式 `and' 式
左辺を評価し、結果が偽であった場合はその値(つまり nil か false) を返します。左辺の評価結果が真であった場合には 右辺を評価しその結果を返します。 and は同じ働きをする優先順位の低い演算子です。
p(nil && false) # => nil
p(false && nil) # => false
p(1 && 2) # => 2
and を伴う式をメソッドの引数に渡す場合は二重に括弧が必要となります。
p(true && false) #=> false
p((true and false)) #=> false
or
例:
demo || die
demo or die
文法:
式 `||' 式
式 or 式
左辺を評価し、結果が真であった場合にはその値を返します。 左辺の評価結果が偽であった場合には右辺を評価し その評価結果を返します。 or は同じ働きをする優先順位の低い演算子です。
p(1 || 2) # => 1
p(nil || false) # => false
p(false || nil) # => nil
or を伴う式をメソッドの引数に渡す場合は二重に括弧が必要となります。
p(false || true) #=> true
p((false or true)) #=> true
not
例:
! me
not me
i != you
文法:
`!' 式
not 式
式の値が真である時偽を、偽である時真を返します。
式 `!=' 式
!(式 == 式)と同じ。
式 `!' 式
!(式 = 式)と同じ。
not を伴う式をメソッドの引数に渡す場合は二重に括弧が必要となります。
p(! false) #=> true
p((not false)) #=> true
優先順位順位の違いとはどういう事かというと、
andと&&はともに論理和となるので同じ結果を返すはずだが
論理和を求めようとして以下のようなコードを記述した場合。
Rubyのコード
result = true and false; p(result) result = true && false; p(result)
実行結果
true false
このようにand演算子と&&演算子では異なる結果を返す。
これはなぜかというと、上記のコードは演算子の優先順位により以下のように解釈される。
Rubyのコード
result = (true and false); p(result) (result = true) && false; p(result)
従って、&&演算子の方は最初に変数resultにtrueを代入した後にその結果に対してfalseとの論理和を演算して、その結果は棄てられてしまう。
これにより、&&演算子の方はtrueという予期せぬ結果になってしまうのである。
従って、このような場合に&&演算子を使って論理和を求める場合は以下のようにかっこ()で囲む必要がある。
Rubyのコード
result = (true && false); p(result)
実行結果
false
Rubyのドキュメントより引用すると
左辺を評価し、結果が偽であった場合はその値(つまり nil か false) を返します。左辺の評価結果が真であった場合には 右辺を評価しその結果を返します。 and は同じ働きをする優先順位の低い演算子です。
...
and を伴う式をメソッドの引数に渡す場合は二重に括弧が必要となります。
...
左辺を評価し、結果が真であった場合にはその値を返します。 左辺の評価結果が偽であった場合には右辺を評価し その評価結果を返します。 or は同じ働きをする優先順位の低い演算子です。
...
or を伴う式をメソッドの引数に渡す場合は二重に括弧が必要となります。
not演算子と!演算子の違いも同様に優先順位にある。
-
perlop - Perl の演算子と優先順位 - perldoc.jp
単項演算子の "not" は右側に来る式の否定を返します。 これは、優先順位がずっと低いことを除いては "!" と等価です。
-
!(式 =~ 式)と同じ。
となっている。
python
以下にブール演算を、優先順位が低い順に示します
演算 | 結果 | 注釈 |
---|---|---|
x or y | x が偽なら y, そうでなければ x | -1 |
x and y | x が偽なら x, そうでなければ y | -2 |
not x | x が偽なら True, そうでなければ False | -3 |
この演算子は短絡評価されます。つまり第一引数が偽のときにのみ、第二引数が評価されます。
この演算子は短絡評価されます。つまり第一引数が真のときにのみ、第二引数が評価されます。
not は非ブール演算子よりも優先度が低いので、 not a == b は not (a == b) と解釈され、 a == not b は構文エラーです。
pythonには&&,||,!演算子は存在しない。
論理演算にはand,or notのみを使う。
論理演算にはand,or notを、ビット演算には,&,|,~をと明確に区別する事はシンプルで解りやすい。
しかし、PerlやRubyのように&&,||,!演算子も使えるという事は、C言語系のプログラマーからは歓迎されるだろう。
どちらが良いかは微妙だ。
result1=False and False result2=False and True result3=True and False result4=True and True print(result1,result2,result3,result4) result1=False or False result2=False or True result3=True or False result4=True or True print(result1,result2,result3,result4)
実行結果
False False False True False True True True False
Pythonでは集合にもand or & | 演算が使える
PHP
PHPもPerlやRubyのようにand,orと&&,||の両方の演算子が存在していて、違いは同様に演算子の優先順位にある。
論理演算子 ¶
論理演算子
例 名前 結果
$a and $b 論理積 $a および $b が共に TRUE の場合に TRUE
$a or $b 論理和 $a または $b のどちらかが TRUE の場合に TRUE
$a xor $b 排他的論理和 $a または $b のどちらかが TRUE でかつ両方とも TRUE でない場合に TRUE
! $a 否定 $a が TRUE でない場合 TRUE
$a && $b 論理積 $a および $b が共に TRUE の場合に TRUE
$a || $b 論理和 $a または $b のどちらかが TRUE の場合に TRUE
"and" および "or" 演算子が 2 種類あるのは、演算が行われる際の優先順位が 異なっているためです (演算子の優先順位 を参照ください)。
しかし、否定演算子についてはPerlやRubyのようなnot演算子は存在せず、!演算子のみとなる。
Pythonとは逆で、pythonがnot演算子のみなのに対して、PHPの場合は!演算子のみとなるので両方の言語を使い分けるプログラマーにとっては注意が必要。
xor演算の違い
andとかor, notという演算子があるならperl(そしてPHP)に存在する排他的論理和であるxorがあってもよいかと思うがrubyとpythonにはこの演算子は存在しない。
以下のコードはエラーになってしまう。
result = True xor False # 結果がFalseになっても良さそうなのだが
実行結果
SyntaxError: invalid syntax
c言語の論理演算子にxorに相当するが存在しないように、rubyやpythonもxorという演算子は存在しないという事なのか。
だけれども、RubyやPythonのご先祖様であるPerlにはxorが存在しているのがまた複雑なところだ。
ビット演算子&
,|
,^
による論理演算
どういうわけか、ビット演算子の&
,|
,^
を論理演算子として使うことができるようである。
result1=False & False result2=False & True result3=True & False result4=True & True print(result1,result2,result3,result4) result1=False | False result2=False | True result3=True | False result4=True | True print(result1,result2,result3,result4)
実行結果
False False False True False True True True
そして、これによってrubyもpythonもビット演算子^
を使って排他的論理和を実現できるようだ。
result1=False ^ False result2=False ^ True result3=True ^ False result4=True ^ True print(result1,result2,result3,result4)
実行結果
False True True False
TrueとFalseのビット演算は1ビットのビット演算という解釈なのかも。
and , or 演算の怪
- 論理演算子(&&, ||)の短絡評価 - Qiita
bool型への暗黙の型変換が行われる言語では、&&や||の左側、右側にくる値はtrueかfalseとは限らない(1や2や3かもしれないし、"aaa"かもしれない)し、また、それらが返す値もtrueやfalseである必要はない。 Cでは、&&や||は、1か0しか返さないが、Perl, Ruby, Python, JavaScriptなどでは、最後に評価した値(つまり、短絡が行われたら演算子の左側の値を、行われなかったら右側の値)を返す。
失敗する可能性のある処理、指定されていない可能性のある引数の評価を行い、 失敗あるいは指定がない場合にデフォルト値を入れる、などの処理が簡単に書ける。
foo = trySomething() || default_value
python
and , or演算をbool値(TrueまたはFalse)以外の型に適用した結果は奇妙だが面白い。
python場合についてみていこう。
以下の論理演算の結果はどうなるであろう。
result = "abc" or 123 print(result)
きっと、"abc"とか123がbool値で無いのでエラーになると思られる方が多いだろう。
ところが結果は
実行結果
abc
では、次の結果はどうなるであろうか
result = 123 or "abc"
実行結果
123
なぜこういう結果になるかというと、前掲のpythonのブール演算に関するドキュメントを思い出してみよう。
「x or y」はx が偽なら y, そうでなければ xと記述されていた。
従って、これらの例では、or演算の左側の値を評価してその値("abc"や123)がTrueとみなされるのでその値が返される事になったのである。
では、左側の値がFalseとみなされる値の場合は右側の値が返される事になる。
更に注目すべき点は異なる型の演算(上記の例でいえば文字列型と数値型の演算)が可能であるという事。
print(0 or "abc") print('' or 123)
実行結果
abc 123
この演算子の性質を積極的に利用すると、変数の値が未定義の場合に初期値を与えるコードを簡潔に記述する事ができる。
# option_var0に値が設定されていない場合はdefalut_valueを代入する option_var0=None option_var0=option_var0 or "defalut_value" print(option_var0) # option_var1になにか値が設定されてる場合はdefalut_valueを代しない option_var1='any_value' option_var1=option_var1 or "defalut_value" print(option_var1)
実行結果
defalut_value any_value
同様にand演算の場合には、「x and y」はx が偽なら x, そうでなければ yと記述されている。
いろいろな場合の例をみてみよう。
# and演算子の場合は左側の値がTrueと評価される場合は右側の値が返される print("123 and \"abc\" => ",123 and "abc") print("\"abc\" and 123 => ", "abc" and 123) # 左側の値がFlseと評価される場合は右側の値が返される print("0 and \"abc\" => ", 0 and "abc") print("'' and 123 => (空文字が返される)",'' and 123 ) # and , or 演算子の引数にはどんな型を指定しても構わない。 # ユーザ定義のクラスのインスタンスを指定 class MyCls: pass print("MyCls() or \"abc\" => ",MyCls() or "abc") # boolean値を指定 print("False or \"abc\" => ",False or "abc") # 両方の引数にブール値True,Falseを指定すれば当然、通常のボール演算の結果と矛盾しない。 print("True or True => ",True or True) print("False or True => ",False or True) print("True or False => ",True or False) print("False or False => ",False or False) print("True and True => ",True and True) print("False and True => ",False and True) print("True and False => ",True and False) print("False and False => ",False and False)
実行結果
123 and "abc" => abc "abc" and 123 => 123 0 and "abc" => 0 '' and 123 => (空文字が返される) MyCls() or "abc" => <__main__.MyCls object at 0x037438D0> False or "abc" => abc True or True => True False or True => True True or False => True False or False => False True and True => True False and True => False True and False => False False and False => False
Perl,RubyもPythonと同じ
この論理演算の性質はPerl,Ruby,PHPでも同じである。
Perl,Ruby,PHPの場合には、論理演算に||や&&も使えるので
perl
# or演算子の場合は左側の値がTrueと評価される場合は左側の値が返される print("abc or 123 =>",("abc" or 123),"\n"); print("abc || 123 =>",("abc" || 123),"\n"); print("123 or abc =>",(123 or "abc"),"\n"); print("123 || abc =>",(123 || "abc"),"\n"); # 左側の値がFlseと評価される場合は右側の値が返される print("0 || abc =>",(0 || "abc"),"\n"); print("'' or 123 =>",('' or 123),"\n"); print("0 || abc =>",(0 || "abc"),"\n"); print("'' || 123 =>",('' || 123),"\n"); # and演算子の場合は左側の値がTrueと評価される場合は右側の値が返される print("123 and abc => ",(123 and "abc"),"\n"); print("123 && abc => ",123 && "abc","\n"); print("abc and 123 => ", ("abc" and 123),"\n"); print("abc && 123 => ", "abc" && 123,"\n"); # 左側の値がFlseと評価される場合は右側の値が返される print("0 and abc => ", (0 and "abc"),"\n"); print("0 && abc => ", 0 && "abc","\n"); print("'' and 123 => (空文字が返される)",('' and 123),"\n"); print("'' && 123 => (空文字が返される)",'' && 123,"\n"); # option_var0に値が設定されていない場合はdefalut_valueを代入する undef($option_var); print($option_var or "defalut_value","\n"); print($option_var || "defalut_value","\n"); # option_var1になにか値が設定されてる場合はdefalut_valueを代しない $option_var='any_value'; print($option_var or "defalut_value","\n"); print($option_var || "defalut_value","\n");
実行結果
abc or 123 =>abc abc || 123 =>abc 123 or abc =>123 123 || abc =>123 0 || abc =>abc '' or 123 =>123 0 || abc =>abc '' || 123 =>123 123 and abc => abc 123 && abc => abc abc and 123 => 123 abc && 123 => 123 0 and abc => 0 0 && abc => 0 '' and 123 => (空文字が返される) '' && 123 => (空文字が返される) defalut_value defalut_value any_valueany_value
ruby
ここで、思わぬ落とし穴、
print("0 || abc =>",(0 || "abc"),"\n");
実行結果
0 || abc =>0
rubyの場合は0や空文字は真なので注意(falseとnilのみが偽と判定される)
# or演算子の場合は左側の値がTrueと評価される場合は左側の値が返される print("abc or 123 =>",("abc" or 123),"\n"); print("abc || 123 =>",("abc" || 123),"\n"); print("123 or abc =>",(123 or "abc"),"\n"); print("123 || abc =>",(123 || "abc"),"\n"); # 左側の値がFlseと評価される場合は右側の値が返される print("false || abc =>",(false || "abc"),"\n"); print("false or 123 =>",(false or 123),"\n"); print("false || abc =>",(false || "abc"),"\n"); print("false || 123 =>",(false || 123),"\n"); # and演算子の場合は左側の値がTrueと評価される場合は右側の値が返される print("123 and abc => ",(123 and "abc"),"\n"); print("123 && abc => ",123 && "abc","\n"); print("abc and 123 => ", ("abc" and 123),"\n"); print("abc && 123 => ", "abc" && 123,"\n"); # 左側の値がFlseと評価される場合は右側の値が返される print("false and abc => ", (false and "abc"),"\n"); print("false && abc => ", false && "abc","\n"); print("false and 123 => ",(false and 123),"\n"); print("false && 123 => ",false && 123,"\n"); print("nil and abc => ", (nil and "abc"),"\n"); print("nil && abc => ", nil && "abc","\n"); print("nil and 123 => ",(nil and 123),"\n"); print("nil && 123 => ",nil && 123,"\n"); # option_varに値が設定されていない場合はdefalut_valueを代入する option_var=nil; print((option_var or "defalut_value"),"\n"); print(option_var || "defalut_value","\n"); # option_var1になにか値が設定されてる場合はdefalut_valueを代しない option_var='any_value'; print((option_var or "defalut_value"),"\n"); print(option_var || "defalut_value","\n");
実行結果
abc or 123 =>abc abc || 123 =>abc 123 or abc =>123 123 || abc =>123 false || abc =>abc false or 123 =>123 false || abc =>abc false || 123 =>123 123 and abc => abc 123 && abc => abc abc and 123 => 123 abc && 123 => 123 false and abc => false false && abc => false false and 123 => false false && 123 => false nil and abc => nil nil && abc => nil nil and 123 => nil nil && 123 => nil defalut_value defalut_value any_value any_value
PHP
PHPの場合には論理演算にboolean型以外の値を指定してもこのような動作にならず、boolean型の値空文字''(FALSE)か1(TRUE)を返す
<?php # or演算子の場合は左側の値がTrueと評価される場合は左側の値が返される echo "abc or 123 =>",("abc" or 123),"\n"; echo "abc || 123 =>",("abc" || 123),"\n"; echo "123 or abc =>",(123 or "abc"),"\n"; echo "123 || abc =>",(123 || "abc"),"\n"; # 左側の値がFlseと評価される場合は右側の値が返される echo "0 || abc =>",(0 || "abc"),"\n"; echo "'' or 123 =>",('' or 123),"\n"; echo "0 || abc =>",(0 || "abc"),"\n"; echo "'' || 123 =>",('' || 123),"\n"; # and演算子の場合は左側の値がTrueと評価される場合は右側の値が返される echo "123 and abc => ",(123 and "abc"),"\n"; echo "123 && abc => ",123 && "abc","\n"; echo "abc and 123 => ", ("abc" and 123),"\n"; echo "abc && 123 => ", "abc" && 123,"\n"; # 左側の値がFlseと評価される場合は右側の値が返される echo "0 and abc => (空文字が返される)", (0 and "abc"),"\n"; echo "0 && abc => (空文字が返される)", 0 && "abc","\n"; echo "'' and 123 => (空文字が返される)",('' and 123),"\n"; echo "'' && 123 => (空文字が返される)",'' && 123,"\n";
実行結果
abc or 123 =>1 abc || 123 =>1 123 or abc =>1 123 || abc =>1 0 || abc =>1 '' or 123 =>1 0 || abc =>1 '' || 123 =>1 123 and abc => 1 123 && abc => 1 abc and 123 => 1 abc && 123 => 1 0 and abc => (空文字が返される) 0 && abc => (空文字が返される) '' and 123 => (空文字が返される) '' && 123 => (空文字が返される)
コンパイラ言語(コンパイラ型言語)では
JavaやC#のように型のチェックが厳しいコンパイラ言語では、&&演算に論理型以外の型を指定する事ができず、このような事はできない。(エラーになってしまう。)
以下のコードはエラーになってしまう。
java
Object result1=123 || "abc"; Object result2=123 || 456;
C#
var result1 = "abc" || 99; var result2 = 123 || 456;
VisualBASICの場合And Or演算に論理型の値を指定した場合は論理値を整数型を指定した場合はビット演算となり、文字列型等それ以外の型を指定した場合はエラーになってしまうようだ。
またc言語のような型チェックが比較的緩い言語でも論理演算の結果は論理値しか返しえない。
printf("123 && abc : %d\n" , 123 && "abc"); printf("NULL && abc : %s\n" , NULL && "abc");
実行結果
123 && abc : 1 NULL && abc : (null)
短絡評価と副作用
論理演算の短絡評価の副作用を積極的に利用する事も多くの言語でできる。