E500BASIC高速化のすべて

PART 9 「BASICだから遅い」は言い訳の言葉


 今までに書いたことをすべて駆使してPART3「VS」をさらに高速化してみました。

《 「VS スーパーターボ」プログラムリスト  》
10 CLS :WAIT 0:CLEAR :LINE (X,12)-(239,18),BF:LINE (Y,21)-(239,27),BF
20 LOCATE 1:PAUSE "READY ";:PRINT "GO!"
30 GCURSOR (X,19):FOR P=X TO 239:IF INKEY$ LET X=P ELSE GPRINT 65;:NEXT :W=2:GOTO 50
40 GCURSOR (Y,28):FOR P=Y TO 239:IF INKEY$ GPRINT 65;:NEXT :W=1 ELSE Y=P:GOTO 30
50 BEEP 1:LOCATE 25,0:WAIT :PRINT W;"P WIN!":GOTO 10

 この「VSスーパーターボ」ではメインルーチン1回当たりの処理時間は6.4m秒(156cps)となっており、「VSターボ」よりも3.4倍も速くなっています。これは一番最初のものと比べると4.6倍速となっています。ここまで速くなっているともはや別格の速度といってもいいかもしれません。これがこのゲームをBASICで作った場合の理論上の最高速度となります。それと同時にプログラムリストのサイズも元のリストが391バイト「VSターボ」365バイト「VSスーパーターボ」348バイトということで速くするのと同時に省メモリも実現できています。

 この6.4m秒(156cps)というのがどれくらいの速度かという参考のために下記の2つの比較対象を用意しました。

リスト1
10 LOCATE 0,0:PRINT "A"
20 GOTO 10

リスト2
10 GCURSOR (0,7):GPRINT "FF"
20 GOTO 10

 リスト1がメインルーチン1回当たり8.6m秒リスト25.8m秒となります。「ただ"A"を表示するだけ」のものよりも速く、「GPRINTで1×8のキャラを表示するだけ」のものとほとんど変わらない速度となっているのです。これで各種判定などをしなくてはいけないゲームとして6.4m秒という速度が非常に高速ということが分かると思います。

ちなみに、「VSスーパーターボ」を作るのに使った高速化テクニックは下記の通りです
(1)省略できるもの(INKEY$の値を一旦別の変数に入れるなど)は可能な限り省略(PART4)
(2)ゲージ減少ルーチンのアルゴリズムを変更(PART5)
(3)表示は最も速いGPRINTで行い、ダブルクォーテーションを省略によって高速化(PART7)
(4)常時必要ではないGCURSORはメインルーチンから出す(PART6)
(5)FOR〜NEXTのカウンタを用いてエネルギー残量の減算処理を省略(PART6)
(6)FOR〜NEXTを用いてエネルギー残量から終了を判断するIF文を省略(PART6)
(7)1P、2Pのメインルーチンを2つに分けFOR〜NEXTで処理することでIF文を省略(PART6)
(8)IF文の簡略化(基本編)による高速化(PART8)

 これらのテクニックはバラバラのものではなくお互いに組み合わさることで実現しています。(7)のようにメインルーチンを1P用、2P用の2つに分けることで(2)のゲージ減少ルーチンのアルゴリズムが簡略化され、(8)のIF文の簡略化も可能になりました。さらに簡略化によって(1)のINKEY$の値を別の変数に入れる必要がなくなりました。さらにメインルーチンを2つに分けることで(4)、(5)、(6)が効果的になりました。メインルーチン1回あたりではIF文による条件判断はキー入力があるか無いかという1回のみとなっています。「VSターボ」では1P側の処理、2P側の処理、ゲーム終了処理の3回行っているのでその分高速化できています。
 このように(3)表示以外の部分はすべて密接に関わり合いを持っています。表示に関してですが、GCURSORの座標が「VSハイスピード」よりY座標が1ドット分ずれているのに気が付いた人もいるかもしれません。これは「VSハイスピード」GPRINT "82"でダブルクォーテーションを省略すればGPRINT 130になるのですがGPRINT 65の方が速くなるからです。このゲームの場合はGPRINT 65Y座標を1ドット分ずらしたものはGPRINT 130と全く変わらないためにGPRINT 65にしています。(厳密には加減乗除など同じ演算子でも数値によって演算時間が異なるので極限の速度を目指すならばその数値さえも重要になる)
 このVSの場合はメインルーチンを2つに分けることが高速化の最大のキーポイントだったわけですが、それが他の場合にも同じように当てはまるとは限りません。下手をすると2つに分けてもプログラムリストが長くなるだけでほとんど速くならないという結果に終わってしまう可能性さえあります。

 何度も書いているように高速化というのは一部分だけを見るのではなく常にリスト全体を見ておくのが重要になります。
PART2で書いたようにメインルーチンの一部だけを高速化しても高速化効果はあまり大きくないからです。一部を高速化しても他の部分がボトルネックとなり思ったように高速化できず、メインルーチン全体を少しずつ高速化していくほうが効果が高くなることが多いです。(たとえメインルーチン実行時間の半分近くを占めている処理であってもその部分だけを何10倍速くしても全体では2倍速にさえならない
 だから、OPASなどの大きな高速化が可能になるテクニックを使えばいとも簡単に3倍速になるということはほとんどなく多種多様のテクニックを駆使する必要があります。とはいえ、要は「(ポケコンにとって)軽い処理に変更(もしくは処理そのものを省略)」すればいいだけであって特別難しいことを行う必要はなくいかにケースバイケースで対応できるかということです。今回は「VS」を限界まで速くするために必要なテクニックは網羅しましたが、これだけですべてのものが十分な高速化ができるというわけではないです。
 ケースバイケースであるため難しいですが、メインルーチン外にメインルーチンを速くするためのポイントが隠されていることもあり、メインルーチン内だけしか見ていないと高速化のポイントを見逃してしまうこともあります。基本的に専用化の度合いを高めることが高速化に繋がることが多いPART5で例に出したじゃんけんの勝敗判定のように汎用性の高いIF文で構成するよりも特定の演算式で行った方が速い場合が多い)ため極論を言うと汎用性を無くせば高速化に繋がるとなるわけですが、実際はそうならない場合もあるし、速くなってもリストが長くなる場合も多いので簡単にはいきません。具体的に全部書くのは無理だからこの辺は経験で覚えて欲しいとしか言えないです。(←「高速化のすべて」というタイトルに偽りありというツッコミは無しの方向で)


 「VSターボ」「VSスーパーターボ」を実際に入力してその速度を自分の目で比較してもらえばBASICの範囲内であっても3倍の高速化が可能という高速化のメリットは十分に分かってもらえたと思いますが、やはりデメリットもあります。それを列記すると下記のようになります。

(1)知識・労力が必要
(2)プログラムリストの可読性が下がる
(3)メインテナンス性が悪い
(4)得られた知識の多くが他への応用が利かない

 (1)知識面に関しては主なものはここで書きましたが、実際のプログラム内で使うにはさらに多くの知識や経験が必要になってきます。どこがボトルネックで遅くなっているのか、どこが高速化のキーポイントとなるのかというのは個々のプログラムで異なりますからね。
 また、BASICの範囲内であるためにBASICが使えれば誰でも可能とはいえ、基本的に地道な改善の積み重ねによって実現されているために誰でも簡単に可能というわけではありません「VSスーパーターボ」のプログラムリストを見ての通り、3倍速くするには根本的な部分から作り直す必要があることが多いためそれと全く同じ動作をするものを別の方法を用いて一から作れなくてはならないですからね。

 (2)可読性に関しては省略できるものは極力省略しているためにプログラムリストは非常に読みにくくなってしまうのはやむを得ないでしょう。これは、インタープリタ方式のポケコンBASICでは速度アップとのトレードオフになるためあきらめてもらうしかありません。(画面の縦が狭いポケコンの場合はマルチステートメントを多用することで可読性はアップするけど)

 (3)高速化は多くの場合、プログラムの汎用性を無くし特定の場合に最適化することで実現しています。したがって、仕様変更に柔軟に対応することはできないことが多くなってしまいます。さらに、バグが見つかった場合の修正が困難になる場合も多くなってしまいます。

 (4)高速化を行うことで得られた知識というのはどれもその機種個別、もしくは特定条件を満たす場合のみしか使えない限定的なものばかりです。したがって、せっかく覚えた知識も多くは他の機種、他の環境で生かすことができません。(アルゴリズムに関しては基本的に言語や環境を選ばないとはいえ速度優先のためポケコンBASIC以外では通用しないものが多い)
 また、そのような特殊なものが多くそれらは現在のプログラミングの手法とは逆行するためにBASICの高速化に慣れてしまうと現在の主流の言語においてプログラミングに支障が出るかもしれません。今回書いた高速化テクニックにおいて違和感や嫌悪感を一切感じず、スムーズかつ好意的に受け入れられる人ならば問題ないですが。


 ポケコンBASICは遅いからこそ高速化のテクニックが有用になってきます。しかし、BASICは習得が容易な言語であり、普通にプログラミングできるレベル(中級者)になればBASICのしかも特定機種でしか通用しないような高速化テクニックよりも他の言語を習得したいと思う人の方が多いのではないでしょうか。
 そもそもBASICの高速化に関するテクニックは上記のような問題点があるため万人に薦められないようなものが多いです。とはいえ速く動作するように作らない限りは速くならないのはどの言語であっても共通であり、速度に不満があるならば高速化という行為は積極的に行うべきだと思います。
 また、私自身PJやベーマガに掲載されているBASICプログラムにおいて平均3倍程度の速度になったという実績があるため逆に言えば、多くの人は(BASICプログラムにおける)ポケコンの性能を30%程度しか使ってないと考えられます。30%程度しか使ってないのに「BASICだから遅い」というのは100点満点のテストで30点しか取れない人が「問題の方が悪い」というのと同じくらいナンセンスなことです。ちなみに私が行ってきた高速化は見た目も動きもオリジナルから変更しない高速化なので画面構成や動きを変えても良いならばさらに高速化が可能です。
 しかし、マシン語を使えば限界まで高速化されたBASICプログラムよりも圧倒的に速くなるためにBASICで高速化しようする行為そのものが馬鹿らしく感じるかもしれません。そのためBASICの高速化は自己満足の域を脱しておらず、そのようなテクニックを身につけても無意味と考える人も少なくないでしょう。

 それでも残りの70%を引き出す(「VSターボ」を「VSスーパーターボ」のようにする)ということに魅力を感じる人はぜひBASICの高速化にチャレンジしてみてください。今までBASICでは難しいと思っていたようなものが作れたり、昔自分でBASICで作って遅すぎたというものが実用レベルになるということも実際に可能です。こうすることにより、「BASICだから遅い」と感じることも減ると思います。
 私は「BASICだから遅い」という言葉を実際に口に出してもいいのはBASICの性能を100%近くまで引き出した後だけだと思います。「ポケコンのBASICはインタープリタ方式だからマシン語よりも遅い」という意味で使っているのならば正しい表現ですが、そうではなく自分が作ったゲームの速度が遅かったりキー反応が悪いのをBASICに責任転嫁する意味で使っていることが大半ですからね。「BASICだから遅い」のではなく遅いゲームを作った「自分自身」に責任があるのです。

 ちなみに、私のBASICの高速化の経験からすると「BASICだから遅い(キー反応が悪い)」といった感じのことを原稿に書いているゲームは例外なく3倍を越える高速化が可能だったのに対してそういうことを書いてないものは3倍の高速化が可能なものはほとんどありませんでした。こういう経験があるからこそ「BASICだから遅い」というのは言い訳にしか見えなくなっているのです。

END


PART 1 なぜBASICを高速化するのか
PART 2 効率的な高速化を行うためには
PART 3 BASICの高速化とは
PART 4 どうやったらBASICが高速化できるのか
PART 5 アルゴリズムの見直し
PART 6 メインルーチンの軽量化
PART 7 表示を高速化
PART 8 IF文をうまく使う
PART 9 「BASICだから遅い」は言い訳の言葉

RETURN

inserted by FC2 system