# 機能設計書 59-Rationalクラス

## 概要

本ドキュメントは、mrubyにおけるRationalクラスの設計を記述する。Rationalクラスは有理数（分数）の演算機能を提供し、分子（numerator）と分母（denominator）のペアとして正確な分数演算を実現する。

### 本機能の処理概要

Rationalクラスは有理数を分子/分母のペアで表現し、自動的に既約分数に約分する。四則演算、比較、型変換をサポートし、BigInt対応で大きな数値の分数演算も可能である。

**業務上の目的・背景**：浮動小数点数の精度限界を回避し、正確な分数計算を行いたい場面がある。金融計算での端数処理、物理定数の正確な表現、比率計算など、精度が重要な計算にはRationalが適している。

**機能の利用シーン**：Rational(1, 3)で1/3を正確に表現、分数同士の四則演算、Float/Integerとの相互変換、Comparable比較など。

**主要な処理内容**：
1. Rational(n, d)でRationalオブジェクト生成（GCDで自動約分）
2. 四則演算: +, -, *, /, **
3. 比較: ==, <=>
4. 型変換: to_i, to_f, to_r, to_s, inspect
5. 属性アクセス: numerator, denominator
6. BigInt対応: 整数オーバーフロー時のBigIntへの透過的フォールバック

**関連システム・外部連携**：Numericクラス（親クラス）、Integer/Float（相互変換）、Complex（複素数との演算連携）、BigInt（大数対応）。

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

## 関連画面

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

## 機能種別

数値計算処理（有理数演算）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| numerator | Integer/Float | Yes | 分子 | 数値型 |
| denominator | Integer/Float | No | 分母（デフォルト1） | 0でないこと |

### 入力データソース

Rubyプログラムからの直接呼び出し（Rational()メソッド、to_r変換）。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Rationalオブジェクト | Rational | 既約分数として表現される有理数 |
| to_i結果 | Integer | 分子/分母の整数除算結果 |
| to_f結果 | Float | 分子/分母の浮動小数点除算結果 |
| to_s結果 | String | "numerator/denominator"形式の文字列 |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. Rational(n, d)の呼び出し
   └─ rational_m()で引数を取得
2. mrb_rational_new(n, d)で内部生成
   └─ dが0ならZeroDivisionError
   └─ dが負ならn, dの符号を反転
   └─ i_gcd(n, d)でGCDを算出
   └─ n/gcd, d/gcdで既約分数に約分
3. RRational構造体を割り当て
   └─ MRB_TT_RATIONAL型
   └─ frozenに設定（イミュータブル）
```

### フローチャート

```mermaid
flowchart TD
    A[Rational n, d] --> B{d == 0?}
    B -->|Yes| C[ZeroDivisionError]
    B -->|No| D{d < 0?}
    D -->|Yes| E[n = -n, d = -d]
    D -->|No| F[i_gcd n, d でGCD算出]
    E --> F
    F --> G[n = n/gcd, d = d/gcd]
    G --> H{オーバーフロー?}
    H -->|Yes| I[BigInt版 rational_new_b]
    H -->|No| J[RRational構造体を割り当て]
    I --> K[frozen設定]
    J --> K
    K --> L[Rationalオブジェクト返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-59-01 | 自動約分 | 生成時にGCDで既約分数に約分される | Rational生成時 |
| BR-59-02 | 分母の正規化 | 分母は常に正の値に正規化される | 常時 |
| BR-59-03 | ゼロ除算禁止 | 分母が0の場合ZeroDivisionErrorを発生 | Rational生成時 |
| BR-59-04 | イミュータブル | Rationalオブジェクトは生成後にfrozenとなる | 常時 |
| BR-59-05 | BigIntフォールバック | 整数オーバーフロー時にBigIntベースのRationalに移行 | RAT_BIGINT有効時 |
| BR-59-06 | 型変換優先順位 | Rational同士: Rational、Float混在: Float | 四則演算時 |

### 計算ロジック

- GCD算出: バイナリGCDアルゴリズム（i_gcd関数）
- 加算: (a/b) + (c/d) = (a*d + c*b) / (b*d)
- 減算: (a/b) - (c/d) = (a*d - c*b) / (b*d)
- 乗算: (a/b) * (c/d) = (a*c) / (b*d)
- 除算: (a/b) / (c/d) = (a*d) / (b*c)
- Float変換: (mrb_float)numerator / (mrb_float)denominator
- Float→Rational: frexp()で仮数部と指数部を分解して正確に変換

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ZeroDivisionError | 分母が0 | 0以外の分母を指定 |
| - | RangeError | 整数オーバーフロー（BigInt無効時） | BigIntを有効化 |
| - | TypeError | 変換不可能な型 | 数値型を指定 |

### リトライ仕様

リトライ不要。

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

該当なし。

## パフォーマンス要件

- RATIONAL_INLINEマクロにより、構造体サイズが許す場合はインライン配置（ヒープ割り当て回避）
- バイナリGCDアルゴリズムにより除算なしでGCDを高速算出
- 整数オーバーフロー検出にmrb_int_mul_overflow等のコンパイラ組み込みを使用

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

特になし。

## 備考

- MRB_TT_RATIONAL型のオブジェクトとして実装
- Kernel#Rationalメソッドはプライベートメソッドとして定義
- Integer#to_r, Float#to_r, NilClass#to_rの変換メソッドも提供
- mrblib/rational.rbでinspect, to_s, <=>等のRubyメソッドを定義
- MRB_USE_COMPLEX時にComplex型との相互変換をサポート

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | rational.c | `mrbgems/mruby-rational/src/rational.c` | struct mrb_rational: 分子/分母のペア（20-41行目） |
| 1-2 | rational.c | `mrbgems/mruby-rational/src/rational.c` | struct RRational: Rationalオブジェクトのヘッダ（47-68行目） |
| 1-3 | rational.c | `mrbgems/mruby-rational/src/rational.c` | RAT_BIGINT/RAT_BIGINT_Pマクロ: BigInt対応判定（34-35行目） |

**読解のコツ**: BigInt対応時、struct mrb_rationalは2つのunionメンバーを持つ。通常のInteger版（i.num/i.den）とBigInt版（b.num/b.den）がある。RAT_BIGINT_P(obj)でどちらが使用されているかを判定する。

#### Step 2: 生成とGCDを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | rational.c | `mrbgems/mruby-rational/src/rational.c` | i_gcd(): バイナリGCDアルゴリズム（207-246行目） |
| 2-2 | rational.c | `mrbgems/mruby-rational/src/rational.c` | mrb_rational_new(): Rational生成+約分（277-308行目） |
| 2-3 | rational.c | `mrbgems/mruby-rational/src/rational.c` | rational_new_f(): Float→Rational変換（328-369行目） |

**主要処理フロー**:
- **280-282行目**: 分母0のゼロ除算チェック
- **292-295行目**: 分母負の場合の符号反転
- **297-299行目**: GCDで約分
- **306行目**: rat->frozen = 1 でイミュータブル化

#### Step 3: 四則演算を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | rational.c | `mrbgems/mruby-rational/src/rational.c` | mrb_rational_add(): 加算（783-836行目） |
| 3-2 | rational.c | `mrbgems/mruby-rational/src/rational.c` | mrb_rational_sub(): 減算（887-941行目） |
| 3-3 | rational.c | `mrbgems/mruby-rational/src/rational.c` | mrb_rational_mul(): 乗算（988-1039行目） |
| 3-4 | rational.c | `mrbgems/mruby-rational/src/rational.c` | mrb_rational_div(): 除算（1088-1141行目） |

#### Step 4: Rubyメソッドとgem初期化を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | rational.rb | `mrbgems/mruby-rational/mrblib/rational.rb` | inspect/to_s/<=>の定義（1-66行目） |
| 4-2 | rational.c | `mrbgems/mruby-rational/src/rational.c` | ROM entries: メソッドテーブル定義（1231-1249行目） |
| 4-3 | rational.c | `mrbgems/mruby-rational/src/rational.c` | gem_init: クラス/メソッド登録（1251-1264行目） |

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

```
Kernel#Rational(n, d)  [rational_m]
    |
    +-- rational_new(a, b)
         |
         +-- [Integer, Integer] -> rational_new_i -> mrb_rational_new
         |    +-- i_gcd() [GCD算出]
         |    +-- 約分
         |    +-- rat_alloc() [構造体割り当て]
         |
         +-- [BigInt] -> rational_new_b
         |    +-- mrb_bint_reduce() [BigInt約分]
         |
         +-- [Float] -> rational_new_f
              +-- frexp() [仮数部+指数部分解]
              +-- rational_new_i or rational_new_b

Rational#+ / #- / #* / #/
    |
    +-- mrb_rational_add/sub/mul/div
         +-- [Integer] -> 直接計算
         +-- [Rational] -> 分数演算
         +-- [Float] -> Float結果
         +-- [BigInt] -> rat_add_b/sub_b/mul_b/div_b
```

### データフロー図

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

n (Integer/Float) ──────> mrb_rational_new()  ──────────> Rational (frozen)
d (Integer/Float) ──────>   |                              (numerator/denominator)
                            +-- ゼロ除算チェック
                            +-- 符号正規化
                            +-- GCD約分
                            +-- freeze

Rational + Rational ────> mrb_rational_add()  ──────────> Rational (新規)
                            +-- (a*d + c*b) / (b*d)
                            +-- GCD約分
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| rational.c | `mrbgems/mruby-rational/src/rational.c` | ソース | Rationalクラスの主要C実装 |
| rational.rb | `mrbgems/mruby-rational/mrblib/rational.rb` | ソース | inspect/to_s/<=>のRuby実装 |
| rational.rb | `mrbgems/mruby-rational/test/rational.rb` | テスト | Rationalクラスの動作テスト |
| mrbgem.rake | `mrbgems/mruby-rational/mrbgem.rake` | 設定 | gemメタデータ定義 |
