【クイズで学ぶ】JavaScriptの乱数|Math.random()とcrypto、UUIDの使い分け

こんにちは!Reiです ‎(˵ •̀ ᴗ – ˵) ✧


突然ですが…、

その乱数、本当に大丈夫ですか?


なんとなくで Math.random() を使っちゃっていませんか?

使い方によってはちょっと危ないな〜んてことも…。


今回はクイズ形式で、乱数の基本と知らないとハマりやすいポイントについて確認していきます!

1問目から意外と迷っちゃうかも…!?


第1問 Math.random() の範囲は?

まずはここから!

console.log(Math.random());

Math.random() が返す値の範囲はどれでしょうか?

  1. 0 以上 1 以下
  2. 0 以上 1 未満
  3. 1 以上 100 以下の整数

正解は… (ここをクリック!)

1の「0 以上 1 未満」です!


解説 !!

Math.random() は、0.1234… のような0 以上 1 未満の小数を返します。


ポイントは「1は含まれない」という点です。

そのままだと整数として扱う場面では使いにくいため、
Math.floor() と組み合わせることがよくあります。


例えば1〜10 の整数をランダムで出したい場合、このように書きます↓

const min = 1;
const max = 10;
const result = Math.floor(Math.random() * (max - min + 1)) + min;

Math.random() に (max – min + 1) を掛けることで、値の範囲を「0以上1未満」から「0以上10未満」に広げています。
その後、Math.floor() を使って小数点以下を切り捨てつつ、min を足すことで、値を「1〜10」の整数の範囲にずらしています。


Math.random() の乱数生成は、「0以上1未満」しか出せないことを押さえておいてください 👀


第2問 パスワード用トークンに使っていい?

次はこちら!

パスワードリセット用のトークンや、 認証まわりの値を作るときに Math.random() を使ってもよいでしょうか?

  1. 使ってよい
  2. 使わないほうがよい
  3. 桁数を増やせば問題ない

正解は… (ここをクリック!)

→ 2. 使わないほうがよい


解説 !!

Math.random() は便利ですが、セキュリティ用途には向いていません。

理由は、完全にランダムな値ではなく、計算によって生成される「疑似乱数」だからです!
そのため、理論上は値のパターンを予測される可能性があります 💦


こういったセキュリティ用途では、 crypto.getRandomValues() を使います 💡
crypto.getRandomValues() は、ブラウザが提供している暗号学的に安全な乱数生成(CSPRNG)で、予測が困難な値を生成することができます!


const array = new Uint32Array(1); // 32ビットの整数(0〜約42億)を入れる配列
crypto.getRandomValues(array); // arrayの中にランダム値をセット

console.log(array[0]); // 例: 2948571203~

このようなに、予測されにくい値を生成でき、トークンや認証に関わる処理で使われています。

「ランダムなら何でも同じ」ではないというのがポイントです 💡


補足💡crypto.getRandomValues() の引数について
crypto.getRandomValues() は通常の配列では引数として使えず、Uint32Array などの「TypedArray(型付き配列)」を利用する必要があります。


第3問 重み付き乱数はどう作る?

次はこちら!

ガチャのように A = 10%B = 30%C = 60% の確率で出したいとき、 どう考えるのがよいでしょうか?

  1. 毎回 Math.random() を3回呼んで比べる
  2. 0〜1 の範囲を割合ごとに区切って判定する
  3. 配列を並び替えて先頭を返す

正解は… (ここをクリック!)

→2. 0〜1 の範囲を割合ごとに区切って判定する


解説 !!

A = 10%B = 30%C = 60% のように、確率に差をつけて結果を出す方法のことを重み付き乱数と言います。

重み付き乱数は、Math.random() の結果が「どの範囲に入るか」で結果を決めるのが基本。


const r = Math.random();

if (r < 0.1) {
  console.log("A");
} else if (r < 0.4) {
  console.log("B");
} else {
  console.log("C");
}

このように、0〜1 の範囲を確率に応じて区切ることで、意図した割合で結果を出すことができます。


ポイントは「累積で考える」こと 💡

それぞれの確率をそのまま使うのではなく、前から順に足し合わせていきます。

A = 0.1
B = 0.1 + 0.3 = 0.4
C = 残り

このように累積していくことで、シンプルに条件を組み立てることができます。

今回のようなケースは「ランダムに選ぶ」というより、「範囲で振り分けている」イメージで処理すること!


ガチャや抽選機能を作るときは、 この考え方を知っておくと組み立てやすいんですよ ‎(˵ •̀ ᴗ – ˵) ✧


第4問 一意なIDがほしいときは?

最後の問題はこちら!

重複しにくい ID をすぐ作りたいとき、 今の JavaScript で使いやすい方法はどれでしょうか?

  1. crypto.randomUUID()
  2. Math.random().toString()
  3. Date.now() だけを使う

正解は… (ここをクリック!)

→ 2. crypto.randomUUID()


解説 !!

crypto.randomUUID() は、UUID v4 形式の文字列を生成するメソッドです。

UUID v4 とは、ランダムな値を使って生成される一意な識別子の形式のひとつで、データのIDや一時的な識別子などに使われています。


const id = crypto.randomUUID();
console.log(id); // 例: "3f29c9c2-6c3e-4c1a-9f5b-8e2d7a6c1f2a"

このように、ランダム性を持った一意なIDを簡単に作ることができます。


一時的な識別子や、重複を避けたい値を作る場面でよく使われ、自分で乱数を組み合わせる必要がないため、手軽に使えるのが特徴です!

※完全に重複しないことが保証されるわけではありませんが、実用上は十分に一意性が高い値です。


補足💡 randomUUID() と乱数の違い
randomUUID() は「IDを作ること」に特化した機能で、単純な乱数とは目的が異なります。「ランダムな値が欲しい」のか、「識別子が欲しいのか」で使い分けるのがポイントです。


ここまでのポイントおさらい !!

今回の内容をまとめると、次のとおり↓

Math.random()
・0以上1未満の小数を返す
・「1は含まれない」ことが重要
・整数にしたい場合は変換が必要


セキュリティ用途の乱数
・Math.random() は安全ではない(疑似乱数)
・予測される可能性がある
・crypto.getRandomValues() を使う


重み付き乱数
・確率に応じて範囲を分けて判定する
・累積で考えるとシンプルに書ける
・「選ぶ」ではなく「振り分ける」


一意なID
・crypto.randomUUID() で簡単に生成できる
・UUID v4 はランダムな識別子
・IDと乱数は目的が異なる


乱数は単純そうに見えて、用途によって考え方が変わってくるので、
「表示用のランダム」なのか、
「セキュリティに関わる値」なのか、
「識別子がほしい」のかで使い分けるのがとっても大切 💡


最後に

何のための乱数なのかを先に考え使ってみると、意味を持たせたコードにすることができるになります。

普段の UI やゲームっぽい処理なら Math.random()、 セキュリティ用途なら crypto 系、 ID がほしいなら crypto.randomUUID() というように、少し意識をして使い分けていくだけで、すごすごエンジニアに一歩近づけます‎(˵ •̀ ᴗ – ˵) ✧

コメント

タイトルとURLをコピーしました