【MONOEYES】Run Run連続再生の確率
A Mirage In The Sun - MONOEYES
実はMONOEYES「A Mirage In The Sun」収録の「Run Run」を、俺は2曲持っている。
A Mirage In The Sunを購入するよりも前にiTunesでRun Runだけ購入してしまったのである。
その後になってA Mirage In The Sunを購入・iTunesライブラリにインポートしたので、
結果的に「A Mirage In The Sun」の「Run Run」が俺のiTunesライブラリ上では全く同じ曲が2曲存在していることになっている。
要するにRun Run1曲分余分に金を使っていることになる(あほ)。
Run Runを結構気に入ってしまって、PVばっか見ていたのだが、
あほらしくなったのでRun Runだけ買っちまえ!
⇒めっちゃええやんアルバムごと買っちまえ!
という経緯によるものである。
こういう場合、A Mirage In The Sun全体をシャッフル再生すると、
当然「Run Run」だけはどっかで2回流れることになるが、
そうなるとこの確率はどんなもんなんだ?というのが(懲りずに)また少し気になり始めた。
というのもどうもA Mirage In The Sunシャッフルをしていると、
Run Runが連続する確率が高いように感じたのである。
以前の検証において、ストレイテナーのSILLY PARADEが連続する確率は0.00367%という計算結果が出ているが
これは母体の数がA Mirage In The Sunとは比べ物にならないほど大きい(ストレイテナー全手持ちの曲257曲(当時))からであり
A Mirage In The Sun収録の12曲(実態としてRun Runが1曲かぶってるので俺のiTunesライブラリ上では13曲になっている)を母体数とすれば
ストレイテナーのSILLY PARADE連続よりは確率が高いことは明らかである。
1曲かぶっているRun Runが連続する確率はどれくらいか?
調べてみた。
まずは理論値から追ってみる。
A Mirage In The Sunに収録されているのは12曲だが、Run Runが被ってるので全部で13曲になる。
この13曲をランダムで再生するとき、「Run Run」がどこかのタイミングで連続するケースを考えればよい。
例えば以下のようなケースが考えられる(便宜上、かぶっているRun Runを(1)と(2)でわけている)
(1)Run Run(1)⇒Run Run(2)⇒他11曲
この確率は
1/13*1/12*11/11*10/10*…*1/1
=1/13*1/12
で計算される。
最初の2曲はRun Run(1)が1/13、Run Run(2)が1/12の確率となり、
最初の2曲でRun Runが出そろったので残り11曲は何が流れてもいい計算である。
ここで、Run Run(1)とRun Run(2)は厳密に2曲を分けた考え方であり、
連続さえしていればその順番は問わない(Run Run(2)⇒Run Run(1)でもいい)ため
この確率は順序逆転版も考慮すると2倍になる。
よってこのケースでのRun Run連続再生確率は
1/13*1/12*2
≒0.012821…
となる。百分率にすると約1.3%弱というところである。この時点で割と高い。
同様の連続ケースは
(2)Run Run2曲を除く11曲のどれか⇒Run Run(1)⇒Run Run(2)⇒残り9曲のどれか
(3)Run Run2曲を除く11曲のどれか⇒Run Run2曲を除く残り10曲のどれか⇒Run Run(1)⇒Run Run(2)⇒残り8曲のどれか
…
というように連続する部分を1つずつずらしていくと全12ケースを考えることができる。
計算してみればわかるのだが各ケースで↑と同じ確率が導かれるので、
全体として「Run Runが連続する確率」は
(1/13*1/12*2)*12
≒0.153846…
という計算結果になる。
百分率で表すと約15.4%。これはかなり高い。
本当にこのくらいの確率になるのか、簡単なシミュレータプログラムを作って検証してみる。
プログラムは以下のとおりである。
import java.util.*; import java.text.*; import java.io.*; public class AMirageInTheSunShuffleSimulation { private static final File RESULT_FILE = new File("shuffle_result.txt"); private static final int SIMULATE_COUNT = 100000; private static final DateFormat YYYYMMDDHHmmSSsss = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS"); private static final int LOG_COUNT = 10000; private static final String[] A_Mirage_In_The_Sun = new String[] { "Cold Reaction" ,"Like We've Never Lost" ,"Just A Little More Time" ,"My Instant Song" ,"Run Run(1)" ,"Run Run(2)" ,"グラニート" ,"End Of The Story" ,"Do I Have To Bleed Again" ,"Get Me Down" ,"明日公園で" ,"Wish It Was Snowing Out" ,"Remember Me" }; public static void main(String[] args) { try { printLog("1.Start"); shuffleSimulation(); printLog("2.End"); } catch(Throwable e) { e.printStackTrace(); } } private static void shuffleSimulation() throws Throwable { BufferedWriter bw = null; int runrunContinuityCount = 0; try { bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(RESULT_FILE))); for (int i=0; i < SIMULATE_COUNT; i++) { // 今回曲目リストを取得 String musicListString = makeShuffleList(); // Run Runが連続しているかチェック boolean isRunRunContinuity = isRunRunContinuity(musicListString); if(isRunRunContinuity) { runrunContinuityCount++; } // 結果ファイルへの出力文字列を生成 StringBuilder sb = new StringBuilder(); sb.append(String.valueOf(i+1)); sb.append(" "); sb.append(String.valueOf(isRunRunContinuity == true ? "○" : "×")); String[] musicArray = musicListString.split("\t"); for (int j=0; j < musicArray.length; j++) { sb.append(" "); sb.append(musicArray[j]); } bw.write(sb.toString()); bw.newLine(); bw.flush(); if (i > 0 && i % LOG_COUNT == 0) { printLog(" Current Round[" + String.valueOf(i) + "]"); } } double runrunContinuityProbability = (double)runrunContinuityCount / (double)SIMULATE_COUNT * 100.00; DecimalFormat dc = new DecimalFormat("00.000"); printLog("総シャッフル回数 :" + String.valueOf(SIMULATE_COUNT)); printLog("Run Run連続回数 :" + String.valueOf(runrunContinuityCount)); printLog("Run Run連続再生確率:" + dc.format(runrunContinuityProbability) + "%"); } catch(Throwable e) { throw e; } finally { if (bw != null) { bw.close(); } } } private static String makeShuffleList() { ListmusicList = new ArrayList(); for (int i=0; i < A_Mirage_In_The_Sun.length; i++) { musicList.add(A_Mirage_In_The_Sun[i]); } StringBuilder musicListString = new StringBuilder(); while (musicList.size() > 0) { int randomIndex = (int)(Math.random() * musicList.size()); String music = musicList.get(randomIndex); musicList.remove(randomIndex); musicListString.append(music); musicListString.append(" "); } return musicListString.substring(0 , musicListString.length() - 1); } private static boolean isRunRunContinuity(String musicListString) { boolean result = false; String beforeMusic = ""; String[] musicArray = musicListString.split("\t"); for (int i=0; i < musicArray.length; i++) { // 1曲目ならbeforeMusicに曲名設定して速攻で次の曲へ if (i == 0) { beforeMusic = musicArray[i]; continue; } // 今の曲と前の曲がともに「Run Run」で始まってたら連続とみなす String currentMusic = musicArray[i]; if (beforeMusic.startsWith("Run Run") && currentMusic.startsWith("Run Run")) { return true; } else { beforeMusic = currentMusic; } } return false; } private static void printLog(Object msg) { StringBuilder sb = new StringBuilder(); sb.append(YYYYMMDDHHmmSSsss.format(new Date())); sb.append(" "); if (msg != null) { sb.append(msg.toString()); } System.out.println(sb.toString()); } }
100,000(10万回)シャッフルしてその中で「Run Run」が何回連続するかを計算する。
各回でRun Runが連続したかどうかを○か×であらわし、その曲目リストそのものをTAB区切りで繋げてファイルにも出力している。
結果は15.439%となった。
理論値に比較的近い(理論値よりは少し高めだ)が概ね予想通りといったところである。
というわけで約15.4%の確率でRun Runが連続することになるようだ。
つまり100回シャッフル再生したらうち15回はRun Runが連続している可能性が高いことになる。
10回シャッフル再生してもうち最低1回はRun Runが連続している可能性が高いとみなせる。
そりゃ高頻度だなと感じるだろう。
冒頭述べたとおりストレイテナーのSILLY PARADEと比べると、
母体数の違いもあってはるかに高い確率となった。
こうした事情もあってかRun Runを聴きすぎて最早歌詞を暗記してしまった。
昔のSpace Sonicに近いものがある。
どうでもいいけど細美って英語歌詞にやたら「just」を使う気がする。
気のせいかね。