プログラミングで使う「乱数」は、ゲームの偶然やシミュレーションのばらつき、鍵やトークンの生成まで幅広く登場します。
本記事では、よく使う疑似乱数と真性乱数の違いを、初学者向けに例えと実務目線でやさしく解説します。
さらに、どの場面でどちらを選ぶべきか、失敗しにくいAPIの選び方や注意点も整理します。
読み終えたら、日常のコーディングで迷わず決められるようになります。
乱数とは?プログラミングでの意味
乱数の定義とランダム性
やさしい定義
乱数とは、次の値が予測しづらい数の並びのことです。
プログラミングでは多くの場合、計算手順で作るため、表面上はバラバラに見えても内部的には規則があります。
これを疑似乱数と呼び、物理的なゆらぎから得るものを真性乱数と呼びます。
乱数の性質を直感でつかむ
乱数にはいくつかの性質があり、用途により重視点が変わります。
「均一に散らばること」「互いに独立っぽいこと」「再現できるかどうか」が初学者が押さえるべき基礎です。
特に再現性はデバッグや実験で役立ちます。
乱数の用途
よくある場面
乱数は、ゲームのアイテム抽選、テストデータの生成、Monte Carlo法のシミュレーション、UI演出のゆらぎ、セキュリティ用の鍵やトークン生成などに使われます。
同じ「乱数」でも、求める性質は場面ごとに違います。
用途と必要な性質の対応表
| 用途 | 重視する性質 | 具体例 |
|---|---|---|
| シミュレーション | 再現性、速度 | 結果を再計算できるようシード固定 |
| ゲーム・演出 | 見た目の不規則さ、速度 | エフェクトのゆらぎ、ドロップ抽選 |
| テスト | 再現性、簡便さ | 疑似乱数で固定シード |
| セキュリティ | 予測不能性、品質 | パスワード、トークン、鍵の生成 |
| 抽選・くじ | 公平性、説明可能性 | ログと方法の公開で納得性を担保 |
セキュリティ用途は「予測不能性」が最優先で、一般の疑似乱数APIは使いません。
疑似乱数の基礎
仕組みのイメージ
レシピとスタート地点
疑似乱数は、ある初期値(シード)から決まったレシピで数を作り続ける仕組みです。
レシピは数学的な手順ですが、初学者は「同じ材料と手順なら同じ料理ができる」とイメージすれば十分です。
代表的な手法にメルセンヌ・ツイスタやXorshift、PCGなどがあります。
周期という考え方
疑似乱数にはいつか同じ並びに戻る「周期」があります。
近年の良いアルゴリズムは周期が非常に長く、通常のアプリでは気にしなくて大丈夫です。
シード(seed)と再現性
固定シードで同じ結果を得る
同じシードを使うと同じ順序の乱数が再現できます。
これは実験やテストの比較にとても便利です。
逆に、毎回違う結果にしたいときは、現在時刻などからシードを変えます。
セキュリティでは固定シードは禁物
秘密情報の生成に固定シードを使うのは厳禁です。
攻撃者にシードを推測されると全体が予測されます。
セキュリティ用途では後述のセキュア乱数APIを使います。
シード管理の実務
実験の再現性が必要なときは、使ったシードをログに残すと後で助かります。
複数スレッドや分散実行では、シードの衝突を避ける設計も大切です。
長所
疑似乱数の長所は、高速で軽く、再現性を持てる点です。
良いアルゴリズムを選べば均一性も十分で、ゲーム、シミュレーション、テストなど多くの用途で頼りになります。
ブロッキングせず安定して供給できるのも使いやすさの理由です。
短所
疑似乱数の弱点は、原理的に決定的(予測可能)であることです。
特にセキュリティでは致命的になります。
- セキュリティ用途には使えません。Math.randomや一般のRandomはトークンや鍵に不可。
- 範囲の作り方次第で偏りが出ることがあります。例えば「rand()%n」のような割り算の余りは均等にならない場合があります。
- 古いアルゴリズムや実装は品質が低い場合があります。
向いている用途
疑似乱数は、結果を何度も検証したいシミュレーションやテスト、演出のゆらぎ、非セキュアな抽選に向いています。
ゲームのドロップ率調整や、データのシャッフル、サンプル抽出など、日常の多くの場面で主役になります。
主なAPI
代表的な疑似乱数APIとセキュアAPIの対比
| 言語/環境 | 一般PRNG(API例・非セキュア) | セキュア乱数(API例・参考) |
|---|---|---|
| Python | random.Random, randomモジュール | secrets, os.urandom |
| JavaScript | Math.random | Web Cryptoのcrypto.getRandomValues |
| Java | java.util.Random, SplittableRandom | java.security.SecureRandom |
| C#/.NET | System.Random | System.Security.Cryptography.RandomNumberGenerator |
| C++ | <random>のmt19937など | OSやライブラリ経由のセキュアAPIを利用 |
| Go | math/rand | crypto/rand |
| Rust | rand::rngs::StdRng | rand::rngs::OsRng |
| Ruby | Random | SecureRandom |
左列は高速で便利ですが秘密情報には使いません。
セキュリティが絡む場面は右列のAPIを選びます。
真性乱数の基礎
仕組みのイメージ
物理のゆらぎを数字にする
真性乱数は、熱雑音や放射性崩壊、光のゆらぎなど自然現象の予測不能な揺らぎを観測して数に変えます。
センサーからの生データには偏りがあるため、ソフトウェアで均一に整える処理(ホワイトニング)を行います。
OSとの関係
多くのOSは、ハードウェアのゆらぎを集めて内部のセキュア乱数生成器(CSPRNG)を育てる仕組みを持ちます。
開発者は直接TRNGに触らなくても、セキュアAPIを呼ぶだけで十分な予測不能性を得られます。
特徴
真性乱数の特徴は、再現できないことと高い予測不能性です。
その代わり、速度や入手のしやすさは環境に依存します。
実機依存でスループットが変わるため、たくさん必要なときはOSのセキュアAPIが内部で賢くバランスを取ります。
向いている用途
真性乱数は、秘密鍵や初期化ベクトルなどのセキュリティに関わる重要値の種として適しています。
公的な抽選や研究用途でも使われます。
ただし一般のアプリ開発では、OSやライブラリのセキュア乱数APIを使うのが現実的です。
入手方法
主な入手経路と注意点
| 入手経路 | 例 | 注意点 |
|---|---|---|
| CPU内蔵ハードウェア乱数 | Intel RDRAND/RDSEED, ARM TRNG | OSが集約して提供するので通常は直接呼ばずセキュアAPI経由で利用 |
| 専用デバイス | USB接続TRNG, HSM, TPM | 導入コストや運用が必要。高い保証が欲しい場合に検討 |
| 組み込みマイコンのTRNG | STM32等のRNGペリフェラル | 実装品質の確認が重要。出力の後処理も考慮 |
| 外部サービス | random.org, NIST Randomness Beacon | ネット越しの乱数は秘密用途に不向き。信頼や改ざん耐性の検討が必須 |
| OSのセキュア乱数API | getrandom, /dev/urandom, BCryptGenRandom等 | 最も実務的。内部でTRNG由来のエントロピーを活用したCSPRNGを提供 |
初学者は「OSのセキュア乱数APIを使う」が基本と覚えておくと迷いません。
疑似乱数と真性乱数の違いと使い分け
違いの要点
| 観点 | 疑似乱数(PRNG) | 真性乱数(TRNG) |
|---|---|---|
| 仕組み | 決定的な手順で生成 | 物理現象から取得 |
| 再現性 | あり(シード次第) | なし |
| 速度・供給量 | 高速で大量に出せる | 環境依存で遅め |
| 予測不能性 | 原理的に弱い | 原理的に強い |
| 実務の使いやすさ | とても使いやすい | 機材/環境の制約あり |
| セキュリティ | 不向き。代わりにCSPRNGを使う | 種として有用。通常はOS経由で活用 |
日常開発はPRNGか、セキュリティならOSのセキュア乱数(CSPRNG)が基本、TRNGを直接扱うのは特殊ケースです。
用途別の選び方
シミュレーション・検証
固定シードのPRNGを使うと、同じ条件で結果を比較できます。
パラメータ調整や回帰テストに向きます。
UI/ゲームの演出
見た目のランダムさが目的なら、PRNGで十分です。
プレイヤー体験の一貫性を担保したい場合は、ステージごとにシードを固定すると便利です。
抽選・サンプリング
公平性が重要ですがセキュリティ機密ではない場合、高品質PRNGを使い、方法とシードの扱いを公開して納得性を高めます。
セキュリティ(鍵・トークン)
常にOSやライブラリのセキュア乱数API(CSPRNG)を使用します。
PRNGのRandomやMath.randomは使いません。
セキュリティでの選び方
セキュリティでは、暗号学的擬似乱数生成器(CSPRNG)のAPIを使います。
これはOSが集めたエントロピーを種にし、予測困難な出力を提供します。
固定シード、時刻だけのシード、独自自作の乱数器は避けるのが鉄則です。
具体的には、Pythonならsecrets、JavaならSecureRandom、JSならcrypto.getRandomValuesのようなAPIを選びます。
よくある間違い
- Math.randomやSystem.Randomでパスワード/トークンを作る。対策: セキュアAPIを使う。
- 「rand()%n」で範囲を作り偏りが出る。対策: 分布APIや適切なサンプリング手法を使う。
- 実験でシードを記録しない。対策: シードをログに残す。
- マルチスレッド/分散で同じシードを使い系列が衝突。対策: 系列を分ける仕組みを設ける。
- セキュア用途で固定シードや時刻シードを使う。対策: OSのセキュア乱数APIに一本化。
初学者のチェックリスト
- 目的は何ですか(シミュレーション/演出/セキュリティ)。用途を言葉にする。
- 再現性は必要ですか。必要ならシードを固定し、記録します。
- セキュリティが関わりますか。関わるならセキュア乱数API一択です。
- 範囲の作り方は偏りを生みませんか。分布APIや安全な方法を選びます。
- 実行環境は同じですか。環境差で結果が変わる点を理解します。
- 大量に必要ですか。必要ならPRNGの速度を活かし、セキュリティはCSPRNGを使用します。
- シードや方法をドキュメント化しましたか。後で再現・説明できる状態にします。
まとめ
疑似乱数は「速くて再現できる」実務の主力、真性乱数は「予測不能」でセキュリティや公的抽選で重要という整理が出発点です。
日常の開発では、高品質なPRNGで十分な場面が多く、セキュリティが絡むときだけOSやライブラリのセキュア乱数APIを使うと覚えておくと迷いません。
シードの扱いと範囲の作り方を丁寧に設計すれば、初学者でも安全で納得感のある乱数利用ができます。
最後に、用途→性質→APIの順に決める癖をつけると、間違いがぐっと減ります。
