Fisher-Yatesシャッフルの仕組み
本ツールが採用しているシャッフルアルゴリズムが「公平」と言える根拠を、計算量と確率の観点から見ていきます。
参照した一次情報
- ・Wikipedia「Fisher–Yates shuffle」(en.wikipedia.org/wiki/Fisher–Yates_shuffle)
- ・Fisher, R. A.; Yates, F. (1938). Statistical tables for biological, agricultural and medical research(オリジナル論文)
- ・Durstenfeld, R. (1964). Algorithm 235: Random permutation. Communications of the ACM 7 (7): 420
アルゴリズムの概要
Fisher-Yatesシャッフルは、配列の末尾から先頭に向けて反復し、各ステップで「自分以下のインデックスからランダムに1つ選び、その要素と現在の位置を交換する」操作を繰り返します。 1938年にFisherとYatesが乱数表で手計算するために発表した手法を、1964年DurstenfeldがコンピュータでO(n)時間に改良した版を「Modern Fisher–Yates」と呼びます。本ツールもこの方式を採用しています。
擬似コードで書くと次の通りです。
for i from n−1 downto 1 do
j ← random integer such that 0 ≤ j ≤ i
exchange a[j] and a[i]なぜ「等確率」が保証されるのか
配列の長さがnなら、可能な並び(順列)はn!通りです。Fisher-Yatesは各ステップで {0, 1, ..., i} から一つランダムに選ぶので、選び方の総数は n × (n−1) × ... × 1 = n! 通り。 各選択は独立かつ等確率なので、最終的な並びもn!通りそれぞれが 1/n! の確率で出現します。
これは数学的に証明されており、Wikipediaも「each permutation of the input has equal probability」と明記しています。 つまり「ある人だけ当選しやすい・順番が早くなりやすい」という偏りは原理的に存在しません。
よくある実装ミス:単純なswap
初学者が書きがちな「全インデックスからランダムに1つ選んで現在位置とswap」する素朴な実装は、確率分布に偏りが生じます。 長さnの配列に対して n回のランダム選択を行うと、選び方の総数は n^n となり、n!の倍数になりません。そのため一部の並びが他より高い確率で出現します。
// 偏りのある実装(やってはいけない)
for i from 0 to n−1 do
j ← random integer such that 0 ≤ j ≤ n−1 // ←nではなくiまでが正解
exchange a[j] and a[i]Wikipediaはこの実装ミスを「naive shuffle」と呼び、可能性のあるn^n通りがn!で割り切れないため等確率にならないことを実証しています。 本ツールはこの罠を避け、必ず「自分以下のインデックスから選ぶ」Modern Fisher-Yates方式を実装しています。
計算量と実用性
- ・時間計算量:O(n) 配列を1回なめるだけ。1万人の応募者でも一瞬で完了します
- ・空間計算量:O(1) 元配列をその場で並び替えるためメモリ追加なし
- ・安定性:同値要素の元の順序は保持されない(並び替え目的なので問題なし)
- ・真の乱数依存:選ぶ乱数の質が悪いと偏りが生じるため、本ツールは暗号学的乱数を組み合わせて使用
3人の例で動きを追ってみる
[A, B, C] をシャッフルする例。配列の末尾(インデックス2)から開始します。
- i=2のとき、{0, 1, 2} から乱数で1つ選ぶ。仮にj=0なら A と C を交換 → [C, B, A]
- i=1のとき、{0, 1} から乱数で1つ選ぶ。仮にj=1なら B と B を交換 → [C, B, A]
- i=0で終了。結果は [C, B, A]
選び方は 3 × 2 × 1 = 6通り、起こりうる並びも3! = 6通りで一致するため、どの並びも1/6の確率で出現します。 この対応関係が「Fisher-Yatesは等確率」の数学的根拠です。
本ツールでの位置づけ
本ツールは Modern Fisher-Yates(Durstenfeld版)を crypto.getRandomValues() の暗号学的乱数と組み合わせて実装しています。 これにより「アルゴリズム的にも乱数源としても偏りがない」二重の公平性を実現しています。
応募者2名の単純なじゃんけんから1000名の懸賞当選者選びまで、同じアルゴリズムでO(n)で実行できるため、人数を増やしても結果は瞬時に表示されます。
関連ツール・記事
- ・ランダム抽選・順番決め本体
- ・公平な抽選のための乱数の話
- ・プレゼント企画で守るべき景品表示法
- ・ルーレット(回転演出で抽選を盛り上げる)