「時間を扱いたい(らしいね>自分)」にて:
時間を排除するのではなくて、時間が流れること/順番・手順に従い物事が進むのを認めて、時間を含むプログラムのモデルを作るべきじゃないか、と思うのです。
これってどういうことか? 簡単な実例を挙げます。
内容:
- 例題:論理ANDを求める
- p AND q の結果はどうなるか
- p AND q の実行時間はどうなるか
- もっと現実的な考慮
例題:論理ANDを求める
pとqを真偽値だとします。つまり、p, qはtrueかfalse。論理ANDの演算を記号∧で表すとすると、p∧p (p AND q)の値は次のように決まります。
p↓q→ | true | false |
---|---|---|
true | true | false |
false | false | false |
論理学の話としては、これでオシマイです。
今度はプログラムの話をしましょう。pとqは真偽値を返すプログラムだとします。p, qはプロセスとして走って、最後にtrueかfalseを返して終わる、としましょう。実際、シェル言語では、プロセスの終了コード(ステイタス)を真偽値と解釈します。
「時間が流れること/順番・手順に従い物事が進むのを認めて」考えると、単一の論理演算子∧では済みません。実行結果の論理ANDを求めるには、次の4つくらいの手順が思い浮かびます。まだ他の手順もあるでしょう。
- pを実行して結果を記録して、次にqを実行した結果と∧演算をして返す。
- pを実行して結果がfalseだったらすぐにfalseを返す。trueだったら次にqを実行した結果を返す。(qの実行を省略するときがある。)
- pとqを同時に実行して、早く終わったほうの結果をどっかに記録しておく。もう一方の終了を待って、両方の結果に∧演算をして返す。
- pとqを同時に実行して、早く終わったほうの結果がfalseだったらすぐにfalseを返す。もう一方は、それ以上走らせても無駄でモッタイナイので中断(強制終了)する*1。trueだったらもう一方の結果を返す。
それぞれやり方が違うので、別な演算記号を割り当てることにします(ここだけの記号)。
- p ;& q (順次で実行省略なし)
- p && q (順次で実行省略あり)
- p &;& q (同時で実行中断なし)
- p &&& q (同時で実行中断あり)
p AND q の結果はどうなるか
プログラムは無限ループに陥って結果を出さないこともあるので、いつまで待っても結果が出ないことを⊥で表します。4つの演算 ;&、&&、&;&、&&& の真偽表は次のようになります。
p ;& q (順次で実行省略なし)
p↓q→ | true | false | ⊥ |
---|---|---|---|
true | true | false | ⊥ |
false | false | false | ⊥ |
⊥ | ⊥ | ⊥ | ⊥ |
p && q (順次で実行省略あり)
p↓q→ | true | false | ⊥ |
---|---|---|---|
true | true | false | ⊥ |
false | false | false | false |
⊥ | ⊥ | ⊥ | ⊥ |
p &;& q (同時で実行中断なし)
p↓q→ | true | false | ⊥ |
---|---|---|---|
true | true | false | ⊥ |
false | false | false | ⊥ |
⊥ | ⊥ | ⊥ | ⊥ |
p &&& q (同時で実行中断あり)
p↓q→ | true | false | ⊥ |
---|---|---|---|
true | true | false | ⊥ |
false | false | false | false |
⊥ | ⊥ | false | ⊥ |
p AND q の実行時間はどうなるか
「p ;& q (順次で実行省略なし)」と「p &;& q (同時で実行中断なし)」の真偽表は同じです。しかし、実行時間は違います。p, qが正常終了したときの実行時間(適当な単位で測った整数値)をn, mとします。無限走行なら実行時間は∞です。
p ;& q (順次で実行省略なし)
p↓q→ | true | false | ⊥ |
---|---|---|---|
true | n + m | n + m | ∞ |
false | n + m | n + m | ∞ |
⊥ | ∞ | ∞ | ∞ |
p && q (順次で実行省略あり)
p↓q→ | true | false | ⊥ |
---|---|---|---|
true | n + m | n + m | ∞ |
false | n | n | n |
⊥ | ∞ | ∞ | ∞ |
p &;& q (同時で実行中断なし)
p↓q→ | true | false | ⊥ |
---|---|---|---|
true | max(n, m) | max(n, m) | ∞ |
false | max(n, m) | max(n, m) | ∞ |
⊥ | ∞ | ∞ | ∞ |
p &&& q (同時で実行中断あり)
[追記]下の表が間違っていたので修正。
見出しを除いて3×3行列と考えて:
- 1行2列: min(n, m) → m
- 2行1列: min(n, m) → n
[/追記]
p↓q→ | true | false | ⊥ |
---|---|---|---|
true | max(n, m) | m | ∞ |
false | n | min(n, m) | n |
⊥ | ∞ | m | ∞ |
もっと現実的な考慮
無限に走るプログラムを待たされるのはイヤだとしたら、適当な整数Nを決めて、N単位時間までに結果が出ないならあきらめる、という方法があります。あきらめたときの真偽値はtrueでしょうかfalseでしょうか? どっちでもないですよね。「ワカンナイ」を意味するindefを真偽値に追加すると、これは⊥とは別物です。このへんのことは、今回の記事の元ネタである「3値または4値の論理の使いどころ」に書いてあります。
実行時間に関するより詳しいことは、「プログラムの実行時間を計る事と半環の代数」にあります。
*1:モッタイナイと考えないなら、単に放置してもかまいません。