出典(authority):フリー百科事典『ウィキペディア(Wikipedia)』「2018/10/29 23:16:39」(JST)
番兵(ばんぺい、英語:sentinel)は基地、野営地の出入りを警備する任務に付く兵士を指す。歩哨とも言う。
転じてプログラミング用語としては、データの終了を示すために配置される特殊なデータを指す。番人(ばんにん)とも言う。以下ではこの意味について示す。
実際にはこの用語は、微妙に異なる以下の2つの意味で使われる。
主に可変長データの終了を識別するために、終了を示す記号として予約された値。
番兵の具体例としては、LISPで無効値を示すNILや、C言語の文字列終端を示すヌル文字(
番兵を含むデータを処理するプログラムは、通常はループで入力データを処理しており、新たなデータを取得するとまず番兵か否かを判定する条件分岐を実行する。以下に、C言語における文字列比較関数 strcmp
の実装例を示す。
int strcmp(const char s[], const char t[])
{
int i = 0;
while (s[i] != '' && t[i] != '' ) {
/* どちらかの文字列に番兵が現れたら終了 */
if (s[i] != t[i]) {
break; /* 不一致箇所を検出したら終了 */
} else {
i++; /* 一致している場合は次の文字へ */
}
}
return s[i] - t[i];
}
実データに出現する値だと、実データなのか終了なのか判断できないため、実データとしては出現しない値を使う必要がある。C言語の getchar
関数では、入力データとして char
型のすべての値が出現する可能性があるため、char
型の範囲では番兵のための値を確保することができない。そのため getchar
関数の返値の型は、より広い範囲の値を扱える int
型になっており、入力データを unsigned char
型の範囲の値として扱い、unsigned char
型としては出現しない値を番兵EOFとして使用している(-1を使う処理系が多い)。
コンピュータで可変長データを表現する方法は、末尾に番兵を置く方法と、長さを別途与える方法の2種類に大別できる。
ループの終了条件が複数ある場合に、条件判定の数を削減するために置くダミーのデータ。この意味での番兵を使った最適化技法を番兵法(-ほう)と呼ぶ。
まず、1の語義に近い例を見る。
以下のC言語プログラムは、整数 entry
と要素数 len
の配列 a
が与えられたときに、a[i] <= entry < a[i+1]
となる添字 i
を求める。ただし a[len-1] <= entry
のときは、a[len]
は存在しないが、len-1
を返す。また entry < a[0]
のときは -1
を返す。
int selectEdge(int entry, int a[], size_t len)
{
int i;
for (i = len - 1; i >= 0; i--) {
if (a[i] <= entry)
break;
}
return i;
}
このプログラムには、ループ終了判定として i >= 0
と a[i] <= entry
の2つの条件が現れる。しかし、a[0]
にダミーのデータとして、常に a[0] < entry
を満たす値を入れておけば、以下のように単一の終了条件に書き直すこともできる。
int selectEdge(int entry, int a[], size_t len)
{
int i;
for (i = len - 1; ; i--) {
if (a[i] <= entry)
break;
}
return i;
}
番兵法はループ中の条件判断を削減できるため、実行時間の削減が非常に重要な場合によく検討される。1 回の条件判断にかかる時間は短くても、ループで繰り返す場合には大きな差となる場合がある。しかしソース上で終了条件がわかりにくくなる可能性も高く、現代の高速化したコンピュータにおいては必ずしも歓迎される技法ではない。採用にあたっては、その利点・欠点を十分に考慮する必要がある。
)などがある。また、ポインタを扱う言語ではヌルポインタが定義されており、線形リストや木構造などの終端を示すために使われる。
番兵を含むデータを処理するプログラムは、通常はループで入力データを処理しており、新たなデータを取得するとまず番兵か否かを判定する条件分岐を実行する。以下に、C言語における文字列比較関数 strcmp
の実装例を示す。
<span></span><span class="kt">int</span> <span class="nf">strcmp</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span> <span class="n">s</span><span class="p">[],</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">t</span><span class="p">[])</span>
<span class="p">{</span>
<span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">while</span> <span class="p">(</span><span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">!=</span> <span class="sc">'<add_contents_exp><m=6 date=20151019>'</span> <span class="o">&&</span> <span class="n">t</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">!=</span> <span class="sc">'<add_contents_exp><m=6 date=20151019>'</span><span class="p">)</span> <span class="p">{</span>
<span class="cm">/* どちらかの文字列に番兵が現れたら終了 */</span>
<span class="k">if</span> <span class="p">(</span><span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">!=</span> <span class="n">t</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="p">{</span>
<span class="k">break</span><span class="p">;</span> <span class="cm">/* 不一致箇所を検出したら終了 */</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="n">i</span><span class="o">++</span><span class="p">;</span> <span class="cm">/* 一致している場合は次の文字へ */</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">-</span> <span class="n">t</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
<span class="p">}</span>
実データに出現する値だと、実データなのか終了なのか判断できないため、実データとしては出現しない値を使う必要がある。C言語の getchar
関数では、入力データとして char
型のすべての値が出現する可能性があるため、char
型の範囲では番兵のための値を確保することができない。そのため getchar
関数の返値の型は、より広い範囲の値を扱える int
型になっており、入力データを unsigned char
型の範囲の値として扱い、unsigned char
型としては出現しない値を番兵EOFとして使用している(-1を使う処理系が多い)。
コンピュータで可変長データを表現する方法は、末尾に番兵を置く方法と、長さを別途与える方法の2種類に大別できる。
ループの終了条件が複数ある場合に、条件判定の数を削減するために置くダミーのデータ。この意味での番兵を使った最適化技法を番兵法(-ほう)と呼ぶ。
まず、1の語義に近い例を見る。
以下のC言語プログラムは、整数 entry
と要素数 len
の配列 a
が与えられたときに、a[i] <= entry < a[i+1]
となる添字 i
を求める。ただし a[len-1] <= entry
のときは、a[len]
は存在しないが、len-1
を返す。また entry < a[0]
のときは -1
を返す。
<span></span><span class="kt">int</span> <span class="nf">selectEdge</span><span class="p">(</span><span class="kt">int</span> <span class="n">entry</span><span class="p">,</span> <span class="kt">int</span> <span class="n">a</span><span class="p">[],</span> <span class="kt">size_t</span> <span class="n">len</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">int</span> <span class="n">i</span><span class="p">;</span>
<span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="n">len</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">>=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o">--</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o"><=</span> <span class="n">entry</span><span class="p">)</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">i</span><span class="p">;</span>
<span class="p">}</span>
このプログラムには、ループ終了判定として i >= 0
と a[i] <= entry
の2つの条件が現れる。しかし、a[0]
にダミーのデータとして、常に a[0] < entry
を満たす値を入れておけば、以下のように単一の終了条件に書き直すこともできる。
<span></span><span class="kt">int</span> <span class="nf">selectEdge</span><span class="p">(</span><span class="kt">int</span> <span class="n">entry</span><span class="p">,</span> <span class="kt">int</span> <span class="n">a</span><span class="p">[],</span> <span class="kt">size_t</span> <span class="n">len</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">int</span> <span class="n">i</span><span class="p">;</span>
<span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="n">len</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="p">;</span> <span class="n">i</span><span class="o">--</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o"><=</span> <span class="n">entry</span><span class="p">)</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">i</span><span class="p">;</span>
<span class="p">}</span>
番兵法はループ中の条件判断を削減できるため、実行時間の削減が非常に重要な場合によく検討される。1 回の条件判断にかかる時間は短くても、ループで繰り返す場合には大きな差となる場合がある。しかしソース上で終了条件がわかりにくくなる可能性も高く、現代の高速化したコンピュータにおいては必ずしも歓迎される技法ではない。採用にあたっては、その利点・欠点を十分に考慮する必要がある。
</raw>
</toggledisplay>
リンク元 | 「歩哨」「sentinel」「センチネル」 |
.