1.はじめに
X(旧Twitter)のタイムラインで「ゲームでは1%の確率で100回に一度は当たらないと暴れる人が結構おられる」のでテーブルを参照することで一定の回数で必ず当たるようなロジックにしていると言うメッセージを見かけ成程なぁと思いました。
Z80で乱数を実装する場合、従来は合同法を使っていましたが、テーブル引き(以降、テーブル方式と記す)にすれば合同法で必要な乗算処理も不要になり、高速化できると言うメリットもあります。
今回はタイムラインからの情報をもとにZ80でのテーブル方式の乱数発生の高速化について書いてみたいと思います。
2.テーブル方式
タイムラインで書かれているようにテーブル方式では要素数を256とし、テーブルを xx00h に配置することで高速化できます。
例えば下記のようにすれば 53 ステートで乱数発生処理を実装できます。
|
3.テーブル方式の高速化案
テーブル内の値に重複が無い場合には、乱数テーブルをリスト方式に変換することで次のように 36 ステートまで高速化できます。
| リストテーブルでの高速な乱数生成処理(Z80アセンブラ) |
|
■乱数テーブルのリスト化とは
乱数の値自体をテーブルのインデックスとしてテーブルを順次辿って行った場合に、元データの乱数テーブルの順番通りに辿れる(元データの乱数列をリスト構造で連結する)ようにしたものをここではリスト化した乱数テーブルと表現しています。
乱数テーブルをリスト化する具体的なサンプルコードを以下に示します。GenRndLst()でリスト化の処理を行っています。
※より判り易いように表現を変更 2026/01/12
| 乱数テーブルのリスト化処理の例(C言語) |
|
上記のコードを実行した結果が下記になります。
| 実行結果 |
|
4.まとめ
乱数テーブルをリスト化することでかなり高速になりました。今回提案したリスト方式はテーブル方式と比較して要素値の重複が許されない反面、要素数を少なくした場合でも処理の変更は不要(AND演算等の追加が不要)という特徴があります。また、処理内容はseedの読み込みと書き込みだけで加工処理が全く無いので究極の速度と言えるのではないでしょうか?
乱数テーブルを使った方式は高速な反面、合同法等と比較し、
- 乱数の周期が短い
- メモリ消費が多い
※リスト方式の特徴を追記 2026/01/18
上記で書いた周期が 256 のテーブル方式の乱数は 8bit の Xorshift で代用できるかもしれません。テーブル方式と同様に Xorshift8 は周期内で同じ値が出ることはありませんが、周期が 255 で 0 は出力されません。
8bit の Xorshift の計算式をここで見つけたので、Z80 のアセンブラ用に書いてみたものが下記のソースになります。私がネット上で確認した限りでは Z80 での16bit 版 Xorshift の最速コードは Retro Programming のサイトに書いてあるもので RET を含めないで 20 バイトの 86 クロックと書かれていますが 82 クロックの間違いではないかと思います。
下記の Xorshift8 では RET を含めなければ 17 バイトの 68 クロックになり、16bit 版よりも高速でコードも短くなるので Z80 を実装したレトロなマシンでのゲーム製作等で使えるかもしれませんね。
| Xorshift8 Z80 version(Z80アセンブラ) |
|
参考として seed の初期値が1の場合に発生した乱数値も貼っておきます。周期が 255 なので先頭と末尾が同じ値になっています。
| Xorshift8 で生成された乱数値 |
|
RET を含めなければ 15 バイトで 60 クロックとなり更にコンパクト&高速になりました。
| Xorshift8 Z80 version その2(Z80アセンブラ) |
|
参考として seed の初期値が1の場合に発生した乱数値も貼っておきます。周期が 255 であることも確認できました。
| Xorshift8 で生成された乱数値 その2 |
|
★追記 2026/05/10
上記の「乱数テーブルのリスト化処理の例(C言語)」のソースの中でGenRndTbl()で乱数テーブルを生成しています。
X(旧Twitter)のタイムラインでトランプをシャッフルする処理に関して話題にのぼり、より簡単(高速)にシャッフルする処理はこんな処理ということが判りました。
★追記 2026/05/14
高速なシャッフル処理についてブログにまとめました。
★追記 2026/07/12
Z80 での 16bit の xorshift に関しては「Retro Programming」のサイトが参考になります。

