ヘッダー画像

「ランダム」って本当にランダム?

投稿 2023年3月26日 最終更新 2023年3月26日 専門用語多め

ランダムとは?

「ランダム」とは

日本語で言う無作為。

一般的には、規則性がなく予測が不可能なことを指します。

いわゆる「テキトーに」ってやつですね。

身近なランダム

身近に使用している場面はあるかと思いますが、
今回はソシャゲでよく見る「ガチャ」を例にあげてみます。

提供確率で、キャラごとに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」という、
より品質の高いランダムを生成するクラスが存在します。

簡単なランダムなら問題はないですが、
セキュリティに関係する大事なところでは、こういうランダムを使用しましょう。

まとめ

どうでしたか?

言語によっても数式やシード値、アルゴリズムが変わるため、
かたよりにも誤差はありますが、まさか確立通りでないとは…

みなさんがランダムだと思っていたものが、実はランダムではないかも知れない

そう思うと、見る世界が変わるかもしれませんね。

以上、ここまで見ていただきありがとうございます。

皆さまの快適な開発ライフに、ほんの少しでもお役に立てれば幸いです。

コメント

この記事のコメントはありません。