# 機能設計書 57-Randomクラス

## 概要

本ドキュメントは、mrubyにおけるRandomクラスの設計を記述する。RandomクラスはPCG（Permuted Congruential Generator）アルゴリズムに基づく擬似乱数生成機能を提供し、整数・浮動小数点数・範囲内乱数・ランダムバイト列の生成をサポートする。

### 本機能の処理概要

PCG-XSH-RR（XorShift High, Random Rotate）アルゴリズムで64ビット状態から32ビット出力を生成する擬似乱数生成器を実装する。インスタンスメソッドとクラスメソッドの両方を提供し、Array#shuffle, Array#sampleも追加する。

**業務上の目的・背景**：ゲーム開発、テストデータ生成、シミュレーション、暗号以外のランダム処理など、組み込みシステムにおいても擬似乱数は重要な機能である。PCGアルゴリズムは統計的品質が高く、実装がコンパクトでメモリ効率が良いため、組み込み環境に適している。

**機能の利用シーン**：乱数生成（rand）、シード設定（srand）、配列のシャッフル（shuffle/shuffle!）、配列からのサンプリング（sample）、ランダムバイト列の生成（bytes）。

**主要な処理内容**：
1. PCG-XSH-RRアルゴリズムによる32ビット乱数生成（rand_uint32）
2. 浮動小数点乱数[0.0, 1.0)の生成（rand_real）
3. 範囲指定乱数の生成（整数・浮動小数点・Range対応）
4. モジュロバイアス回避のrejection sampling（rand_i）
5. Fisher-Yatesアルゴリズムによる配列シャッフル
6. ユニークインデックスによるサンプリング

**関連システム・外部連携**：Arrayクラス（shuffle/shuffle!/sample）、Kernelモジュール（rand/srand）。

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | ライブラリ機能であり、画面との直接的関連なし |

## 機能種別

乱数生成処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| seed（initialize/srand） | Integer | No | 乱数シード | 省略時は自動生成 |
| max（rand） | Integer/Float/Range | No | 乱数の上限または範囲 | 正の数、有効なRange |
| size（bytes） | Integer | Yes | 生成するバイト数 | 正の整数 |
| n（sample） | Integer | No | サンプリング数 | 0以上、配列長以下 |

### 入力データソース

Rubyプログラムからの直接呼び出し。time(NULL)によるシード自動生成。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| rand結果 | Integer/Float | 乱数値 |
| srand結果 | Integer | 前回のシード値 |
| bytes結果 | String | ランダムバイト列 |
| shuffle結果 | Array | シャッフルされた配列 |
| sample結果 | Object/Array | サンプリングされた要素 |

### 出力先

呼び出し元のRubyプログラムへの戻り値。

## 処理フロー

### 処理シーケンス

```
1. Random.new(seed) または Random.rand(max)
   └─ rand_state構造体の初期化
2. rand_uint32()でPCG乱数生成
   └─ LCGステップ: state = state * MULTIPLIER + INCREMENT
   └─ XorShift High: xorshifted = ((oldstate >> 18) ^ oldstate) >> 27
   └─ Random Rotate: 結果を上位ビットで回転
3. 出力変換
   └─ 整数: rand_i()でモジュロバイアス回避
   └─ 浮動小数点: x * (1.0/4294967296.0)
   └─ 範囲: rand_range_int() / rand_range_float()
```

### フローチャート

```mermaid
flowchart TD
    A[rand 呼び出し] --> B{引数あり?}
    B -->|No| C[rand_real: 0.0-1.0のfloat]
    B -->|Yes| D{引数の型}
    D -->|Integer| E[rand_i: 0..max-1の整数]
    D -->|Float| F[rand: 0..max-1の整数]
    D -->|Range| G[random_range: 範囲内の値]
    E --> H[rejection samplingでバイアス回避]
    C --> I[rand_uint32 * 1.0/2^32]
    H --> J[rand_uint32でPCG乱数生成]
    I --> J
    G --> K{整数Range?}
    K -->|Yes| L[rand_range_int]
    K -->|No| M[rand_range_float]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-57-01 | PCGアルゴリズム | PCG-XSH-RR方式、64ビット状態、32ビット出力 | 常時 |
| BR-57-02 | モジュロバイアス回避 | rejection samplingでモジュロ演算のバイアスを回避 | rand_i呼び出し時 |
| BR-57-03 | デフォルトインスタンス | Random.rand等のクラスメソッドはデフォルトRandom::DEFAULTを使用 | クラスメソッド呼び出し時 |
| BR-57-04 | プラットフォーム最適化 | 32ビットプラットフォームではPCG_MULTIPLIER = 0xf13283adを使用 | MRB_32BIT定義時 |
| BR-57-05 | シード初期化 | srand省略時はtime(NULL) XOR rand_uint32 XOR ポインタ値でシード生成 | srand引数省略時 |

### 計算ロジック

- PCG LCGステップ: `state = oldstate * PCG_MULTIPLIER + PCG_INCREMENT`
- PCG出力関数: `xorshifted = ((oldstate >> 18) ^ oldstate) >> 27; rot = oldstate >> 59; result = (xorshifted >> rot) | (xorshifted << ((32-rot) & 31))`
- 浮動小数点変換: `x * (1.0 / 4294967296.0)`
- モジュロバイアス回避: `threshold = (-max) % max; do { r = rand_uint32(); } while (r < threshold)`

## データベース操作仕様

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ArgumentError | bytes()に負の値を指定 | 正の整数を指定 |
| - | ArgumentError | sample()に負の値を指定 | 0以上の整数を指定 |
| - | TypeError | 非整数/非Range引数 | 適切な型を指定 |
| - | RuntimeError | デフォルトRandomが置換された場合 | 内部エラー |

### リトライ仕様

リトライ不要。

## トランザクション仕様

該当なし。

## パフォーマンス要件

- rand_uint32()は乗算1回、XOR/シフト数回で完結する高速な乱数生成
- 32ビットプラットフォームでは最適化された乗算器を使用（乗算2回で済む）
- bytes()は4バイト単位でバッチ生成して効率化
- rand_state構造体はISRUCT（インライン構造体）で管理し、ヒープ割り当て不要

## セキュリティ考慮事項

- PCGは暗号学的擬似乱数生成器（CSPRNG）ではない。セキュリティ用途（トークン生成、暗号鍵等）には使用しないこと
- シード値が推測可能な場合、乱数列も推測可能

## 備考

- MRB_TT_ISTRUCTで状態を管理し、GC管理のヒープ割り当てを回避
- デフォルトRandomインスタンスはgem初期化時にtime(NULL)でシードされる
- Kernel#rand/srandはデフォルトRandomインスタンスを使用するプライベートメソッド
- BigInt対応: MRB_USE_BIGINT時にはバイト列ベースのランダムBigInt生成をサポート

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | random.c | `mrbgems/mruby-random/src/random.c` | rand_state構造体: PCG内部状態（41-50行目） |
| 1-2 | random.c | `mrbgems/mruby-random/src/random.c` | PCG_MULTIPLIER/INCREMENT定数（34-39行目） |
| 1-3 | random.c | `mrbgems/mruby-random/src/random.c` | GET_STATE/SET_STATEマクロ（53-63行目） |

**読解のコツ**: 32ビットプラットフォームではuint64_tのstate変数をstate_lo/state_hiに分割して保存し、GET_STATE/SET_STATEマクロで64ビットアクセスを行う。

#### Step 2: 乱数生成コアを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | random.c | `mrbgems/mruby-random/src/random.c` | rand_uint32(): PCG-XSH-RR出力関数（91-106行目） |
| 2-2 | random.c | `mrbgems/mruby-random/src/random.c` | rand_real(): 浮動小数点変換（109-115行目） |
| 2-3 | random.c | `mrbgems/mruby-random/src/random.c` | rand_i(): モジュロバイアス回避（130-156行目） |
| 2-4 | random.c | `mrbgems/mruby-random/src/random.c` | rand_seed(): シード初期化（74-89行目） |

**主要処理フロー**:
- **95行目**: oldstateを保存
- **98行目**: LCGステップでstateを更新
- **101行目**: XorShift Highで上位ビットを混合
- **105行目**: ランダム回転で出力を生成
- **150行目**: rejectionサンプリングでバイアス回避

#### Step 3: Rubyメソッドを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | random.c | `mrbgems/mruby-random/src/random.c` | random_m_rand(): インスタンスrandの実装（304-309行目） |
| 3-2 | random.c | `mrbgems/mruby-random/src/random.c` | random_rand_impl(): rand処理本体（207-243行目） |
| 3-3 | random.c | `mrbgems/mruby-random/src/random.c` | random_m_bytes(): bytesの実装（351-379行目） |
| 3-4 | random.c | `mrbgems/mruby-random/src/random.c` | mrb_ary_shuffle_bang(): shuffle!の実装（405-427行目） |
| 3-5 | random.c | `mrbgems/mruby-random/src/random.c` | mrb_ary_sample(): sampleの実装（460-506行目） |

#### Step 4: gem初期化を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | random.c | `mrbgems/mruby-random/src/random.c` | mrb_mruby_random_gem_init(): メソッド登録（578-604行目） |

**主要処理フロー**:
- **584行目**: Randomクラス定義（MRB_TT_ISTRUCT）
- **591-592行目**: Kernel#rand/srandをプライベートメソッドとして登録
- **594-596行目**: Array#shuffle/shuffle!/sampleを登録
- **598-603行目**: デフォルトRandomインスタンス生成とシード設定

### プログラム呼び出し階層図

```
Random.rand / Kernel#rand
    |
    +-- random_f_rand()
         +-- random_default_state() [デフォルトインスタンス取得]
         +-- random_rand_impl()
              |
              +-- random_rand() [引数なし: rand_real()]
              +-- rand_i() [整数: rejection sampling]
              +-- random_range() [Range: rand_range_int/float]
              |
              +-- rand_uint32() [PCG-XSH-RR コア]

Array#shuffle!
    |
    +-- mrb_ary_shuffle_bang()
         +-- check_random_arg() [Randomオブジェクト取得]
         +-- rand_i() [Fisher-Yatesアルゴリズム]
```

### データフロー図

```
[入力]                     [処理]                         [出力]

seed (Integer)    ───> rand_seed() ──────────────> rand_state更新
max (Integer)     ───> rand_i() ─────────────────> Integer [0, max)
max (Float)       ───> random_rand() ────────────> Integer [0, max)
range (Range)     ───> random_range() ───────────> Integer/Float
size (Integer)    ───> random_m_bytes() ─────────> String (バイト列)
引数なし          ───> rand_real() ──────────────> Float [0.0, 1.0)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| random.c | `mrbgems/mruby-random/src/random.c` | ソース | Randomクラスの全C実装 |
| random.rb | `mrbgems/mruby-random/test/random.rb` | テスト | Randomクラスの動作テスト |
| mrbgem.rake | `mrbgems/mruby-random/mrbgem.rake` | 設定 | gemメタデータ定義 |
