「ランダム」って本当にランダム?
ランダムとは?
「ランダム」とは
日本語で言う無作為。
一般的には、規則性がなく予測が不可能なことを指します。
いわゆる「テキトーに」ってやつですね。
身近なランダム
身近に使用している場面はあるかと思いますが、
今回はソシャゲでよく見る「ガチャ」を例にあげてみます。
提供確率で、キャラごとにn%…
みたいな表記がずらっと書かれているかと思います。
本当に確率通りになるのか?
と、一度は考えたことがあるのではないでしょうか。
今回はその「ランダム」について、語っていきます。
本当にランダムなのか?
例にあげたガチャは本当にランダムなのか?
一概には言えませんが、ランダムとは言えないものも存在しています。
※対策をしているものもあるかと思います
誰がランダムな値を求めている?
そもそも誰が、ランダムなキャラを選んでいるのかと言うと、
最終的には機械(パソコン)が、ランダムな値を求めています。
例のガチャでいうと、ざっくり以下のような流れです。
- ユーザがガチャボタンを押す
- プログラムがランダム関数を実行する
- 機械(パソコン)がランダムな値を求める
- 求めたランダムな値でプログラムがキャラを決定
- キャラを画面に表示
機械が適当?
よく考えてみると、機械がランダム、
いわゆる適当に値を出すことは出来るのか?
機械って言うと必ず同じ動きをする…
と言うか、同じ動きじゃないと困るものですよね。
その機械に「適当に」と言っても、難しい話なのです。
機械にとってのランダムの求め方
ここまで説明すると、なんとなく分かるかもしれませんが、
ちゃんと数式によって値を求めています。
つまり理論上、再現できます。
ただ、その値を人間が見たら、ランダムだと思えるような数式になっています
それを「疑似ランダム関数」と呼びます。
シード値
その関数を使用するには、シード(Seed)値と呼ばれる値を渡してあげる必要があります。
指定せず実行するとプログラム側で
現在時刻だったりプロセスIDだったりと、
特定されにくい値を自動的にシード値として使用します。
結果がかたよる
本題の確率通りに出現するのか?
実は疑似ランダム関数だと、規則性がある数式を使用する関係上
どうしてもかたよってしまいます。
Javaにおけるランダムテスト
Javaでランダムを実行してみました。
import java.util.Random;
public class RandomTest {
public static void main(String[] args) {
// ループ回数
int loopNum = 1000;
// シード値は自動指定で生成
Random random = new Random();
// 出現回数格納配列定義
int[] randomValues = new int[10];
// ランダム生成
for (int i = 0; i < loopNum; i++) {
// 0~9を生成
int randomValue = random.nextInt(10);
randomValues[randomValue]++;
}
// 結果
System.out.println("出現値 : 出現回数/検証回数");
for (int i = 0; i < randomValues.length; i++) {
// 結果を成形して出力
System.out.print(i + " : ");
System.out.print(String.format("%3d", randomValues[i]));
System.out.println("/" + loopNum);
}
}
}
実行結果がこちらです。
出現値 : 出現回数/検証回数
0 : 95/1000
1 : 104/1000
2 : 98/1000
3 : 121/1000
4 : 91/1000
5 : 117/1000
6 : 94/1000
7 : 68/1000
8 : 104/1000
9 : 108/1000
かたよってますね…
何度か実行してみます。
出現値 : 出現回数/検証回数
0 : 89/1000
1 : 97/1000
2 : 79/1000
3 : 102/1000
4 : 108/1000
5 : 114/1000
6 : 110/1000
7 : 94/1000
8 : 96/1000
9 : 111/1000
出現値 : 出現回数/検証回数
0 : 97/1000
1 : 87/1000
2 : 106/1000
3 : 93/1000
4 : 93/1000
5 : 106/1000
6 : 125/1000
7 : 82/1000
8 : 102/1000
9 : 109/1000
出現値 : 出現回数/検証回数
0 : 89/1000
1 : 89/1000
2 : 110/1000
3 : 86/1000
4 : 111/1000
5 : 104/1000
6 : 105/1000
7 : 108/1000
8 : 106/1000
9 : 92/1000
出現値 : 出現回数/検証回数
0 : 88/1000
1 : 107/1000
2 : 116/1000
3 : 109/1000
4 : 104/1000
5 : 88/1000
6 : 97/1000
7 : 105/1000
8 : 107/1000
9 : 79/1000
出現値 : 出現回数/検証回数
0 : 106/1000
1 : 90/1000
2 : 112/1000
3 : 92/1000
4 : 98/1000
5 : 109/1000
6 : 103/1000
7 : 107/1000
8 : 94/1000
9 : 89/1000
高品質のランダム
Javaには「SecureRandom」という、
より品質の高いランダムを生成するクラスが存在します。
簡単なランダムなら問題はないですが、
セキュリティに関係する大事なところでは、こういうランダムを使用しましょう。
まとめ
どうでしたか?
言語によっても数式やシード値、アルゴリズムが変わるため、
かたよりにも誤差はありますが、まさか確立通りでないとは…
みなさんがランダムだと思っていたものが、実はランダムではないかも知れない
そう思うと、見る世界が変わるかもしれませんね。
以上、ここまで見ていただきありがとうございます。
皆さまの快適な開発ライフに、ほんの少しでもお役に立てれば幸いです。