Mersenne Twister 1998 — 日本発の疑似乱数アルゴリズムと用途上の注意
DDEVELOPER
開発(更新: 2026-08-25)9 分で読める

Mersenne Twister 1998 — 日本発の疑似乱数アルゴリズムと用途上の注意

NanToo の サイコロコイントスくじ引きルーレットパスワード生成 など「ランダム」を扱うツールでは、ブラウザの Math.random() または crypto.getRandomValues() を用途ごとに使います。ECMAScript は Math.random() の方式を実装依存とし、Web Crypto も具体的な生成アルゴリズムを固定していないため、どちらも Mersenne Twister の使用を意味しません。Mersenne Twister (MT19937) は1998年に広島大学の松本眞・西村拓士が発表し、多くの言語や科学計算環境で使われてきた代表的な疑似乱数アルゴリズムです。本記事では原論文 (ACM TOMACS, 1998) と松本研の公開資料を一次資料に、その仕組み・用途・暗号には不向きな理由を整理します。

#乱数#Mersenne Twister#MT19937#アルゴリズム#暗号

「乱数」とは何か — 真の乱数 vs 疑似乱数

コンピュータが生成する「乱数」は、ほぼすべて疑似乱数 (PRNG, Pseudo-Random Number Generator)。決定的なアルゴリズムが内部状態を更新しながら数値を吐き続けます。同じ初期値 (seed) を入れれば同じ系列が再現される計算機にとって都合の良い "ランダム"です。

真の乱数は物理現象 (原子崩壊・サーマルノイズ・大気電気) などからしか得られず、ハードウェア乱数源として CPU の RDRAND 命令や Linux の /dev/random が利用しています。一方の疑似乱数は:

  • 長所: 高速、再現可能 (seed を保存すれば再生)、ポータブル
  • 短所: 内部状態を見抜かれると以降が予測可能 (後述)

シミュレーション・ゲーム・統計サンプリングなどでは速度と再現性が重要なので疑似乱数が主流。Mersenne Twister はこの分野の事実上の標準になっています。

Mersenne Twister — 1998 年の革命

1998 年、広島大学の 松本眞西村拓士 が ACM Transactions on Modeling and Computer Simulation に発表した論文 "Mersenne Twister: A 623-Dimensionally Equidistributed Uniform Pseudo-Random Number Generator" が転換点でした。

主要なバリアントは MT19937。名前の由来は内部状態が 2^19937 - 1 = メルセンヌ素数 で、これが乱数列の周期になることから。具体的な性能:

周期: 2^19937 - 1 ≈ 4.3 × 10^6001
状態空間: 624 個の 32-bit 整数 (= 19968 bit)
等分布次元: 623 次元 (各次元で一様に分布)

「周期 2^19937」が何を意味するか: 1 秒間に 10 億個の乱数を生成しても、宇宙の年齢の何兆倍経っても周期が一周しない。実用上は無限と同じです。

等分布次元 623 とは、1 ビットから 623 次元までのベクトル空間で乱数列が一様に分布することを意味します。これは多次元シミュレーション (モンテカルロ法など) で重要で、それまでの線形合同法 (LCG) などと比較して桁違いに優れていました。

アルゴリズムの仕組み (簡略版)

MT19937 のコア:

// 内部状態: 624 個の 32-bit 整数の配列 mt[0..623]
// 1) 初期化 (Knuth の手法)
mt[0] = seed
for i = 1..623:
  mt[i] = 1812433253 * (mt[i-1] xor (mt[i-1] >> 30)) + i

// 2) 624 個の出力ごとに状態を更新 (twist)
for i = 0..623:
  y = (mt[i] & 0x80000000) | (mt[(i+1) mod 624] & 0x7fffffff)
  mt[i] = mt[(i+397) mod 624] xor (y >> 1)
  if (y mod 2 != 0):
    mt[i] = mt[i] xor 0x9908B0DF

// 3) 出力 (tempering で各ビットの偏りを減らす)
y = mt[i]
y = y xor (y >> 11)
y = y xor ((y << 7) & 0x9D2C5680)
y = y xor ((y << 15) & 0xEFC60000)
y = y xor (y >> 18)
return y

1 回の出力ごとに状態を 1 ステップ進め、624 個出した時点で全体を「twist」(ねじり) 操作で大きく更新する設計。シフト・XOR・剰余・乗算しか使わないため 1 出力あたりナノ秒オーダーで高速。

"Mersenne" = メルセンヌ素数 (2^p - 1 の形の素数、ここでは p=19937)、"Twister" = 状態をねじって混ぜる操作 — この 2 つから命名されました。

どこで使われているか — 世界の主要実装

表が収まらない場合は、左右にスクロールできます。

言語/環境実装・位置づけ関数
PythonMT19937random.random() (Python 3.0+)
PHPMT19937mt_rand() (PHP 7.1 以降は rand() も内部で MT)
ExcelMT19937=RAND() (Excel 2010 以降。Excel 2003 では Wichmann-Hill 系列を採用したが品質問題で後に修正された経緯あり)
MATLABMT19937rand() のデフォルト
RMT19937runif() のデフォルト
RubyMT19937Random.new
C++ 11+標準ライブラリが明示的なエンジンとして提供std::mt19937 (<random>)
NumPyMT19937 (default_rng は PCG64)numpy.random.RandomState (legacy)

Mersenne Twister は多くの言語・ライブラリでデフォルトまたは選択可能なエンジンとして採用され、広く普及しました。環境やAPIの世代によって既定値は異なるため、再現性が必要な用途ではアルゴリズム名と版を明示して確認する必要があります。

Hiroshima 大学のサイト 松本研究室公式 で C / Fortran のリファレンス実装が今も配布されています。

JavaScript の Math.random() は何を使っているか

ECMAScript が Math.random() に求めるのは、0以上1未満のおおむね一様な値を、実装依存のアルゴリズムまたは戦略で返すことです。具体的な方式は標準契約ではなく、ブラウザやJavaScriptエンジンの更新で変わり得ます。

したがって、ユーザーエージェント名だけから MT19937 や xorshift 等の方式を断定できません。NanToo の Math.random() を使うツールも特定方式を前提にせず、くじ引きとルーレットは別APIの crypto.getRandomValues() を使用します。

致命的な弱点 — 暗号には絶対使ってはいけない

MT19937 の最大の落とし穴: 暗号学的に安全ではない (Not Cryptographically Secure)

具体的には: 内部状態 624 個の整数 = 19968 ビットを観測できれば、以降のすべての出力を予測できます。実際には連続する 624 個の出力 (32-bit × 624) から内部状態を逆算する手法が公開されており、線形ソルバ等で容易に攻撃可能。

つまり、MT でパスワード・暗号鍵・セッション ID・ノンス・トークンを生成すると、出力を一定数集めるだけで以降が予測でき、深刻な脆弱性につながります。

過去の実例:

  • 2015 年: PHP 5.x の session_id()mt_rand ベースだった件 — 攻撃可能性が指摘され PHP 7 で修正
  • 古いオンラインカジノ・MMO のアイテムドロップ判定が MT で、攻撃者が乱数列を予測してチート可能だった事例多数

セキュリティ用途では暗号学的擬似乱数 (CSPRNG) を使うこと:

  • Web (ブラウザ): crypto.getRandomValues() (Web Crypto API)
  • Node.js: crypto.randomBytes()
  • Python: secrets モジュール (Python 3.6+)、os.urandom()
  • OS レベル: Linux /dev/urandom、Windows BCryptGenRandom

Web Crypto は crypto.getRandomValues() に暗号学的に強い乱数を要求し、OSのエントロピー源など高品質な種を使う確立したCSPRNGを推奨します。ただし、具体的な生成方式やエントロピー源は実装が選び、仕様は情報理論上のエントロピー下限を定めていません。API名だけで特定の内部方式や絶対的な予測不能性まで断定しないことが重要です。

後継アルゴリズム — 2010 年代以降の進化

MT19937 は決して廃止されたわけではありませんが、2010 年代以降に「より小さな状態で同等の品質を出す」「より高速」を目指した PRNG 群が登場しています。

表が収まらない場合は、左右にスクロールできます。

アルゴリズム発表年状態サイズ速度 (相対)
Mersenne Twister (MT19937)1998624 × 32-bit (2.5 KB)1.0× (基準)
WELL512a2006512-bit0.9×
xorshift128+2014128-bit2.5×
xoroshiro128+2018128-bit2.5×
xoshiro256**2018256-bit2.0×
PCG642014128-bit1.5×
SFMT (松本ら)20082.5 KB2-3× (SIMD)

SFMT (SIMD-oriented Fast Mersenne Twister) は同じく松本研の発表で、CPU の SIMD 命令を使い MT を 2-3 倍高速化したもの。2008 年論文発表後、シミュレーション分野で広く採用されています。

「では MT は時代遅れか?」というと NO。**統計品質 (等分布性、独立性) では今でも世界トップクラス**で、新しいアルゴリズムも MT19937 をベンチマークに比較されます。シミュレーション・科学計算・乱数列再現が必要な用途では現在も第一選択です。

本サイトのツール群と乱数

本サイトのランダム系ツールの実装を整理:

表が収まらない場合は、左右にスクロールできます。

ツール使用乱数選定理由
サイコロ crypto.getRandomValues() (CSPRNG) 公開契約と乱数源を一致させ、剰余バイアスも回避
コイントス crypto.getRandomValues() (CSPRNG) 32bit値の1bitを表・裏へ均等に割り当て
くじ引き crypto.getRandomValues() + 棄却サンプリング + Fisher-Yates 32ビット値を交換位置へ偏りなく割り当てるため
ルーレット crypto.getRandomValues() + 棄却サンプリング 32ビット値を候補indexへ偏りなく割り当てるため
パスワード生成 crypto.getRandomValues() + 棄却サンプリング 候補文字への剰余バイアスを避けて割り当てるため

各ツールの乱数源と割り当て方法は上表の実装説明を確認してください。Web Crypto APIの採用だけで、物理抽選との同一性、第三者監査済みの公平性、くじ・賭け等の法的要件が保証されるわけではありません。

まとめ

  • Mersenne Twister (MT19937) は 1998 年広島大学発の疑似乱数アルゴリズム
  • 周期 2^19937 - 1 (メルセンヌ素数)、623 次元等分布
  • 多くの言語・ライブラリでデフォルトまたは選択可能なエンジンとして採用
  • JavaScript Math.random() の具体的な方式はECMAScriptでは実装依存
  • 暗号学的に安全ではない — パスワード・トークン生成には絶対に使わない
  • セキュリティ用途では crypto.getRandomValues() / secrets / os.urandom を使う
  • 本サイトのツールは目的に応じて Math.random と CSPRNG を使い分け

関連 — 確率を計算したくなったら

乱数で「振る」 のと、 数学で「確率を計算する」 のは別の頭の使い方。 振った結果が「珍しい事象だったのか」 を後付けで知りたい場面では、 全パターン列挙の確率計算が便利です。

参考文献・ソース

記事作成に関する注記

本記事は AI(大規模言語モデル)を編集補助として活用して作成しています。 公開前に編集者が内容を確認していますが、事実誤認・仕様の解釈ミス・最新情報との齟齬が含まれる可能性があります。 重要な判断を行う際は、本文中の一次ソースや公式ドキュメントを必ずご自身でご確認ください。 誤りにお気づきの場合は、お問い合わせフォームよりご連絡いただけると助かります。

🔧 関連ツール

📚 関連記事