フィンローダのあっぱれご意見番

第4回:ゼロ要素へ

初出: C MAGAZINE 1992年8月号
Updated: 1996-02-24

[1つ前] [1つ後] [一覧] [ホームページ]


アガサ・クリスティの推理小説に「ゼロ時間へ」というのがある。タイトルだ けでは意味不明だが、要するに逆算タイマーの感覚である。通常、日時というの は、文字通り刻々と増加するものだし、時間を計測する時には0からスタートし て「はいそこまで」というまでの長さを調べるのである。この小説を総論として 考えてみれば、クリスティの作品の中でも特に印象に残る訳でもないのだが、あ る時点を目標に減少していくという違和感だけは印象に残ってしまったのだ。

6月号のリスト2で、


    fp = fopen("test.dat", "rb");
    if (fp != NULL) {
        /* 何か処理する */
        fclose(fp);
    }

と書いたら早速反論が来ました。主旨としては、次のように書いた方が自然で はないかというのである。
    fp = fopen("test.dat", "rb");
    if (fp == NULL) {
        /* エラーの処理をする */
        return; /* 必要なら値を戻す、または exit(); とする */
    }
    fclose(fp);

普通なら「どっちでもいいじゃん」となる所だが、普段「より自然なプログラ ミング」を主張している立場としては、そうも言ってられない。どちらが自然だ とか、これは違和感がある、というのは重要なポイントなのだ。これは難問だが 、ここではとりあえず問題提起に留めておく。この本が書店に並んでいる頃には 決着が付いているかもしれない。
    *
某塾の電車広告に、私立中学の入試問題が掲示されていた。中学の入試問題と いっても侮れない。結構難しい問題もある。先日見たのは、どこの中学の問題か 忘れたが、本にふってあるページの数字に含まれている、1、2、3、…9、0 の数を数えたらn個でした…本当はn個ではない、ちゃんと数字が書いてあった のだが、これも忘れてしまったのだ…さて、この本は何頁までありますか、とい う問題である。

つまり、もしこの本が1頁までの本なら1、2頁なら1と2の2個で2、…1 0頁の本なら1〜9までの9個と10頁には1、0の2個の数字があるので、1 1、という意味である。

この問題自体は何でもないのだが、偶然これを見ていた女子中学生の会話を横 で聞いていると、「最初と最後の数字を足して2で割るのよねぇ」とか言ってい て、訳がわかんない。なお、これは実話ですから、なぜ「女子」中学生なのかは 深く考えてもしょうがないです。

ところで、この問題を見て気になったのは解答ではない。「1、2、3、…9 、0」という数字の順序である。普通のセンスを持っていれば、「0、1、2… 9」となるような気がする。しかし、やはり考えてみると0から始めるのは無理 があるのだ。「一から始める」という言い回しがあるのでわかるように、最初の 数字は1、というイメージが強烈なのである。0から始まっている、という感触 はどうも特殊らしい。というか、0という数字の位置は、あまり直感的でないの かもしれない。想像だが、ここで0という数は、本来の0という意味ではなく、 10という数の下の桁を表現しているイメージとして理解されているのかもしれ ない。

プッシュホンのキー配列を見ても、やはり1から始まって、9の次が*、そし て0、#となっている。


fig.1 数字キーの配列

 1 2 3      7 8 9
 4 5 6      4 5 6
 7 8 9      1 2 3
 * 0 #      0

 プッシュホン     テンキー

今や数少なくなったダイアル式電話機も、1か ら9、0という順番で番号が振られている。どうも通常の感覚ではこちらが自然 なのだろう。これに比べると、キーボードのテンキーの配列は、下から0123 …789という順序になっていて、0は1の近くにある。この配置が電話と統一 できなかった、というか、今だにできないことが実に脅威である。仕様が不統一 になったまま広まってしまうことの恐ろしさを実感できる。

電話といえば、ISDNには掛けた人の電話番号を知るための機能が用意されてい るが、この機能はオプション選択で強制できないそうだ。通信の秘密云々だから 、という理由を聞いた記憶もあるが、実際どうなのだろう。しかし受信者には電 話を受けるかどうか判断する自由があるし、そのための情報が足りない場合に無 視するのは権利の範囲内だと思う。だから、相手の電話番号がわからなければ受 け取らない機能を受信者側に用意するのは全く問題がないと思うのだが。「自分 の電話番号を掛ける相手に知らせる機能」と「掛かってきた電話番号を知る機能 」とは、どちらが自然な解釈だろうか。先入観はアイデアを妨害する。

*
しかし、Cのプログラムを書く人なら「0、1、2、…9」というのが自然な 順序なのだろう。という訳で、C言語を始めた人が最初に「あれっ」と思うのが 、配列である。C言語の配列は、0から始まるからだ。これは一度言われたらほ とんど間違わないものだ。問題は配列のサイズである。リスト1の関数は単なる例 で、これだけでは何の処理もしない。
/* リスト1 */
void sample1(void)
{
    int a[10];
    int i;

    for (i = 0; i < 10; i++) /* ごくありふれた書き方 */
        a[i] = i;
}

え? なぜリスト0からでなくリスト1から 始まるのかって? それは編集の方に尋ねてみてください。

よくある間違いに、リスト2のように書いてしまうというものがある。


/* リスト2 */
void sample2(void)
{
    int a[10];
    int i;

    for (i = 0; i <= 10; i++) /* 間違い */
        a[i] = i;
}

a[10]という配列は、10個の要素が 入る配列という意味であって、従って0から9までの10個の添え字が適正範囲 なのだが、a[10] と変数定義したために、つい a[10] まで使ってしまうのだと思 う。

なお、リスト3のように書いても間違いではない。


/* リスト3 */
void sample3(void)
{
    int a[10];
    int i;

    for (i = 0; i <= 9; i++) /* これでも間違いではない */
        a[i] = i;
}

しかし、リスト1の書き方が 好まれる。配列が a[10]と宣言されているから、10という数字を使った方が間違 いが起こりにくいからだ。このような些細なことも即座にバグという結果に結び 付くので、とにかく主義主張を一貫することが肝心だ。

漠然とした格言だが、配列で書くよりポインタで書く方が速い、という伝説が あった。リスト4のような書き方となる。


/* リスト4 */
void sample4(void)
{
    int *p;
    int a[10];
    int i;

    p = a;

    for (i = 0; i < 10; i++) {
        *p++ = i;
    }
}

しかし、今やコンパイラの最適化技術 が進歩したので、人間が変に凝ったことをすると余計に遅くなることもある。深 く考えると損をするかもしれない。それでも凝るのが趣味なら、アセンブラの出 力を出して比較しながら、一番速そうなコードを出すような書き方を選択する手 はある。もっとも、それはコンパイラがバージョンアップした時点で無駄な努力 に成り下がるという危険を常に含んでいる。

 クリスティの話はどこへ行ったのだ。折角伏線を作ったのだから使い古された ネタだが出しておこう。リスト5のような書き方がある。この場合は、a[10]と定 義しておきながら、iを9から始めなければならないので、結構神経がいらいらす る。


/* リスト5 */
void sample5(void)
{
    int a[10];
    int i;

    for (i = 9; i >= 0; i--) /* 0に向かってループする */
        a[i] = i;
}

このような書き方をする理由は、速度が勝ることがある点に尽きる。CPUの持っ ている命令セットにも依存するが、一般の定数との比較命令に比べて、0という特 定の値と比較する場合には特別な命令があり、処理が高速である場合がある。つ まり、リスト1のように、10という定数と比較してループの終了を判断するよりは 、リスト5のように0と比較した方が、高速化が期待できるというわけだ。ただし、 あくまで期待できるだけで、実際に速くなるとは限らない。それはコンパイラを 作る人のこだわり次第である。

ここで、ループの継続条件は0と比較するのが肝心だから、i > -1 のように比 較すると全てぶち壊しになるかもしれないが、コンパイラを設計した人がそこま で見切っていれば、0と比較するコードに置き換えてくれるかもしれない。


(C) 1992, 1996 Phinloda, All rights reserved
無断でこのページへのリンクを貼ることを承諾します。問い合わせは不要です。
内容は予告なく変更することがあります。