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

第62回:速い話

初出: C MAGAZINE 1997年6月号
Updated: 1997-08-25

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


 今まで耐えがたきを耐えて486DX/66MHzのpcを使っていたのだが、長年の苦労 のかいもあって何とか新マシンを購入することができた。といっても、別段珍し いスペックではなく、ごくありきたりのパソコンである。前マシンは結局 Windows 95のインストールで挫折しているので、今回はプレインストールの状態 のマシンを購入することにした。挫折といっても、モデムカードの認識以外は殆 どうまく行っていたのだが、モデムが使えないとWWWにアクセスできないため話 にならないのである。

 しかし挫折で終わってしまうのもしゃくだから、最後の最後で奥の手を使うこ とにした。モデムカードを認識しないのだから、モデムカードを替えてしまえば よいかもしれない、と考えるのは当然の成り行きである。特に、PlayStation開 発環境が高速で接続できない問題も何かいまいちだから、シリアルポートを高速 化しておき、外付けのモデムにすればいいのである。実は前のpcというのは16550 互換ではなかったため、いい所19200bps程度しか速度が出ていなかったのだ。も ちろん、モデムカードの方は16550互換モードになっているため、Windows 3.1か らは何の問題もなく使えていたわけだが。

 という感じで、モデムカードを引っこ抜いて16550互換のシリアルカードに入 れ替え、SUNTACの外付けモデムを接続した。これが実は1万円しなかったという 代物なのだが、ちゃんと33400kbpsで接続できるし、おまけでNetscape Navigator 3.0まで付いて来るという気の利いたモデムである。店に山積みになっていたが、 このように何か不自然に安いというのもつい手が出てしまうので困る。もっとも、 今時この程度のモデムなら高くても2万円もしないから、極端に安いという訳で もないのだが、Netscape Navigator 3.0だけ買っても5,000円位するのだから、 正味の値段はモデムが5,000円程度という感覚なのだ。

 この組み合わせで前マシンに接続してWindows 95を起動した。PnPはうまく動作 するだろうか。結果から書くと、数回のリブートの後、なんとかうまく動作した ようである。なぜ数回もリブートしなければならないのか、よく分からないのだ が、とりあえず引き分け程度には持ち込んだ所で、新マシンが到着したわけだ。

 新マシンの方は、最初から16550互換のシリアルチップが入っているので、何 の問題もなくモデムを接続できてノープロブレムである。ただ、時々Netscape Navigatorが異常事態になって落ちてしまうのだが、これはまあこんなものと諦 め半分である。おそらく、家庭にインターネットが普及する条件としては、こん なことでは全くお話にならないのだと思うのだが、どちらかというとプログラム を作る側の立場にいることもあって、ソフトウェアの暴走程度は愛嬌だと考えて しまうあたりが怖い。

 新マシンでまず驚いたのは作業用のWeb pageの表示の速さである。TP230Csと 比較するというのが間違っているのかもしれないが、486SX/33MHzのこのマシン だと表示に2分ほどかかっていた「FPROGいろはかるた」のページが、1秒フラッ トで表示完了してしまう。確かにCPUはPentium 200MHzだし、Millenniumの処理 も速いのかもしれないが、それにしても100倍も処理速度が違うとやはり作業の やり方まで変わって来る。昔はちょっとしたCのプログラムでもコンパイルに数 十秒、下手をすれば数分以上かかったものだが、これが1秒とか2秒でコンパイル できるようになると、とりあえずちまちまと変更してすぐにコンパイルする、と いう手順で作業したくなるものだし、その方が効率が良かったりする。ハードウ ェアの進化は作業スタイルを変えてしまうのだ。

*

 またまたPerlの話。しかも失敗談である。昔、fprgfというプログラムを作っ たことがあった。って、これは単なるテキストのfoldをする程度のソフトなのだ が、最近はいろいろ機能追加したいことがあって、その時に手元にソースプログ ラムがたまたまなかったので、ちゃちゃっとPerlのスクリプトに置き換えていた りする。Perlを使ってfoldするというのは基本演習問題のようなもので、単に72 桁で折り返すだけなら簡単である。実際に使うには、行頭だとか行末の処理もし たいし、引用の処理もしたい。NIFTY-Serveの発言のヘッダがあったら、その発 言へのコメントであるというようなマークも入れたい。このような余計な機能を 追加すると当然バグの入り込む余地も増える。

 行頭や行末の処理というのは、いわゆる禁則処理のことである。例えば「。」 という字が行頭に来た場合に、これを前の行の最後に送り込むといった処理をし たいのだ。本来は、文章の途中にCRやLFを入れるという不毛なことはしたくない のだが、NIFTY-Serveのシステムに制限と障害があるため仕方無いのである。こ の点は一行の長さに制限がないHTMLの方が気楽だ。ただ、困ったことにNIFTY-Se rve用に作ったドキュメントは文の途中でバシバシとCRやLFが入るため、ブラウ ザはそこに空白があると解釈してしまい、そのままHTMLにすると見苦しいことが ある。もちろん、これもPerlを使って連結すればいいわけだが、それはさておき、 最初書いたのはList 1のようなスクリプトである。

---- List 1 ----

    if ($tmp =~ /^[。、ー」]/) {
      $t .= substr($tmp, 0, 2);
      $tmp = substr($tmp, 2);
    }

    print "$t\n";

---- List 1 end ----

$tmpには、作業中の行の残りが入っている。$tmpから1行分だけ取り出して、$t という変数に入れる。これを画面に表示する。という仕組みにしてある。だから、 行頭に来て欲しくない文字がある場合というのは、$tmpの先頭がそれらの文字で あるということで、従って$tmpの頭の文字を$tの最後に移してやればよいのだ。 substrなんか使わなくてももう少しスマートな処理もありそうなものだが、とり あえずこれはこれで動作する。

 ところで、行頭に来てほしくない文字はこれだけではない。閉じる括弧という のもそうである。で、このスクリプトをList 2のように修正した。

---- List 2 ----

    if ($tmp =~ /^[。、ー」\]\)\?]/) {
      $t .= substr($tmp, 0, 2);
      $tmp = substr($tmp, 2);
    }

    print "$t\n";

---- List 2 end ----
 つまり、「]」や「)」や「?」が行の頭に来ないようにしたいのである。とこ ろがこれはどう見てもまずい処理である。なぜかというと、これらは1バイトコー ドなので、substrで2バイトも移動してしまうと、次の行の頭がちょっとヤバい ことになるのだ。ところが、これらのコードの直後には空白があるケースが多か ったので、単に行の頭の空白がカットされるだけであり、ぱっと見た目には何と もないし、むしろ余計な空白が取れるのですっきりする。というわけで、このバ グに結構長い間気付かなかったのだ。

---- List 3 ----

    if ($tmp =~ /^[。、ー」]/) {
      $t .= substr($tmp, 0, 2);
      $tmp = substr($tmp, 2);
    } elsif ($tmp =~ /^[\]\)\?]/) {
      $t .= substr($tmp, 0, 1);
      $tmp = substr($tmp, 1);
    }
    print "$t\n";

---- List 3 end ----
 実際に使っているコードはList 3である。こうしないと「)」の直後に2バイト コードが来た場合など、とても変なことになってしまう。

 では、なぜList 2のようなことをしたのだろうか。マッチする文字の追加に気 を取られて、その長さが1かもしれないし2かもしれない、という所にまで配慮で きなかったのだ。この問題を根本的に避けるには、List 4のような処理にすれば よいのである。

---- List 4 ----

    if ($tmp =~ /^([。、ー」\]\)\?])/) {
      $t .= substr($tmp, 0, length($1));
      $tmp = substr($tmp, length($1));
    }

    print "$t\n";

---- List 4 end ----
 では、なぜそういう処理にしなかったかというと、この方が何か遅くなりそう な気がしたわけである。もちろん、length($1)を二回呼び出しているのは誰が見 ても無駄だから一度目で変数を使って値を保持すればよい。もちろん、これはコ ンパイル時に最適化されればどうでもいいことかもしれないし、逆に、最適化が 保証されているのであったら、length($1)と書いた方が可読性の点では優という 考え方もある。しかし、考えてみれば、List 5のようにした方がもっと単純に処 理できるような気もする。

---- List 5 ----

    if ($tmp =~ /^([。、ー」\]\)\?])(.*)$/) {
      $t .= $1;
      $tmp = $2;
    }

    print "$t\n";

---- List 5 end ----
 つまり、Perlの便利な機能の一つ、パターンにマッチした場合に、()でくくっ た内容を順に$1、$2、…に入れてくれる、というのを使うのだ。こうすれば、$t と$tmpがどうなったのか、ということは一見簡単になったように見える。実際簡 単ではないかって? 確かに変数の処理の所は簡単だが、問題はパターンマッチ である。この程度でも、「]」や「)」をマッチさせようとしている影響もあって、 パッと見て瞬間に理解できるかどうか微妙な所である。もちろん考えて分からな い程ではないが、誤解が有りえない程簡単かというと、断言するのもちょっと辛 い。

 こういうことにあれこれ悩むのもいいが、新マシンの速度だと、結局「誤差の 範囲内です」ということになってしまいそうで、やや張り合いがない。贅沢な話 だが、マシンが速過ぎるというのも考え物なのかもしれない。


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