tl;dr
- ブログのURLにランダム値を使うとして、必要なビット数は何桁だろうか
- ハッシュ衝突の問題は「誕生日のパラドックス」と同じ状況設定
- 数学的な裏付けの元で、ランダムビットを28桁確保すれば十分
Intro
「個人ブログのパーマリンクに関する最適戦略について」において、
{{base-url}}
/ blog /{{year}}
/{{random}}
というURLをこのブログに使うことに決めました。しかし、 {{random}}
はどれだけのビット数を使い、どのようなフォーマットを使うべきでしょうか。
幸い、 {{year}}
を入れているので、「永遠」を考える必要はありません。
せいぜい「1年」でどれだけの記事を書くのかを見積れば良いことになります。
毎日、1記事を書いたとして
誕生日のパラドックス
誕生日のパラドックス(たんじょうびのパラドックス、英: birthday paradox)とは「何人集まれば、その中に誕生日が同一の2人(以上)がいる確率が、50%を超えるか?」という問題から生じるパラドックスである。鳩の巣原理より、366人(閏日も考えるなら367人)集まれば確率は100%となるが、しかしその5分の1に満たない70人しか集まらなくても確率は99.9%を超え、50%を超えるのに必要なのはわずか23人である。
誕生日のパラドックスは論理的な矛盾に基づいているという意味でのパラドックスではなく、結果が一般的な直感と反しているという意味でのパラドックスである。
Wikipediaでも計算してありますが、ここでも計算しておきます。
きちんと問題として整理すると以下のようになります。
Aさんを含め、n人がいる。一年を365日とし、誕生日は全ての日で等確率とする。
- Aさんと同じ誕生日の人が存在する確率
- 同じ誕生日の人が存在する確率
と が %を超えるのにそれぞれ必要な人数 ,
Aさんと同じ誕生日の人が存在する確率
余事象で求める。
Aさん以外の人は
の確率でAさんの誕生日と衝突しない。 Aさん以外の人は 人存在するので、同じ誕生日の人が存在する確率
余事象で求める。
n人の誕生日が異なる確率は
よって
と が %を超えるのにそれぞれ必要な人数 , については計算できる。よって
となる。 については面倒なので、Pythonを用いて図示する。import matplotlib.pyplot as plt import numpy as np memo = np.full(400, -1.0) def NPn (n): """ 余事象の確率 n人の誕生日が異なる確率 """ if n == 0 or n == 1: memo[0] = 1 return memo[0] elif n >= 366: return 1; elif memo[n] != -1: return memo[n] else: p = NPn(n-1) * ((365-(n-1))/365.0) memo[n] = p return memo[n] def Pn (n): """ n人のうち、2人以上誕生日が同じ確率 """ return 1 - NPn(n) n = 70 with plt.style.context(('science-transparent')): y = [Pn(i) for i in range(n)] plt.plot(y) plt.xlabel('n') plt.ylabel('P_n') plt.axhline(0.5, color='C1') n_min2 = np.searchsorted(y, 0.5) plt.annotate('({}, {:.2f})'.format(n_min2, y[n_min2]), (n_min2, y[n_min2]), (n_min2-15, 0.8), arrowprops = dict(arrowstyle='-|>', mutation_scale=20)) plt.show()
グラフから、
。
上記のとおり
直感との乖離の理由は「自分と同じ誕生日の人が存在する確率」と「同じ誕生日の組が存在する確率」を混同してしまうからです。
ランダム値の衝突
今回問題にしているようなランダム値の衝突については、 「あるひとつのランダム値が衝突する事象」ではなく、「どれでもいいのでランダム値が衝突する事象」を考える必要があるので、 まさに誕生日のパラドックスと同じ状況設定となります。
誕生日のパラドックスでは365個の集合でしたが、今回は変数
前段の
ここで、ネイピア数のテイラー展開は次の形です。
さらに
数値計算
Nが与えられている場合
ランダム値の大きさ(
最後の近似はオーダーを見積もるためにとても雑な近似を行いました。
もしランダムビットが 64bit の場合、ランダム値の集合は
Nを求めたい場合
逆に今回私は試行回数、1年
衝突する確率
以上、ランダムビット数は28桁あれば十分ということになります。
16進数の表記を使えば1文字で4ビットの自由度があるので、結局、8文字あれば十分ということが分かりました。
まとめ
誕生日のパラドックスを導入としてランダム値の衝突問題(ハッシュ衝突問題)について考えました。
長々書いてきましたが、数学的な裏付けのもとで必要なランダムビット数が分かり、パーマリンクのフォーマットを決めることができました。
次の記事「ox-hugo用のorg-captureテンプレートについて」ではこのフォーマットを実現するためのox-hugoの運用について書きたいと思います。