# 機能設計書 60-Complexクラス

## 概要

本ドキュメントは、mrubyにおけるComplexクラスの設計を記述する。Complexクラスは複素数の演算機能を提供し、実部（real）と虚部（imaginary）のペアとして複素数の四則演算、べき乗、極座標変換等を実現する。

### 本機能の処理概要

Complexクラスは複素数を実部/虚部のペアで表現し、四則演算、べき乗、等値比較、型変換、極座標との相互変換をサポートする。Mathモジュールへの依存を持ち、三角関数・対数関数を利用した高度な複素数演算を提供する。

**業務上の目的・背景**：信号処理、制御工学、電気回路計算、量子コンピューティングのシミュレーション等において複素数は不可欠な数学的概念である。Complex型により、複素数演算をRubyの自然な構文で記述できる。

**機能の利用シーン**：Complex(a, b)で複素数生成、リテラル表記（3+4i）、Complex.polarで極座標から生成、四則演算（+, -, *, /）、べき乗（**）、abs/arg/conjugateによる極座標操作、to_f/to_iによる実数変換。

**主要な処理内容**：
1. Complex(real, imag)でComplexオブジェクト生成
2. 四則演算: +, -, *, /（quo）
3. べき乗: **
4. 比較: ==, <=>
5. 極座標: abs, arg, polar, conjugate
6. 型変換: to_i, to_f, to_r, to_c, to_s, inspect
7. 属性アクセス: real, imaginary(imag)

**関連システム・外部連携**：Numericクラス（親クラス）、Mathモジュール（cos, sin, atan2, hypot, log, exp, pow）、Rationalクラス（to_r変換）、Integer/Float（相互変換）。

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

## 関連画面

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

## 機能種別

数値計算処理（複素数演算）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| real | Float/Integer | Yes | 実部 | 数値型（mrb_as_floatで変換） |
| imaginary | Float/Integer | No | 虚部（デフォルト0.0） | 数値型 |
| abs（polar） | Float | Yes | 極座標の絶対値 | 数値型 |
| arg（polar） | Float | No | 極座標の偏角（デフォルト0） | 数値型 |

### 入力データソース

Rubyプログラムからの直接呼び出し（Complex()メソッド、Complex.rectangular、Complex.polar、リテラル表記 `a+bi`）。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Complexオブジェクト | Complex | 実部/虚部のペアとしての複素数 |
| to_i結果 | Integer | 虚部が0の場合の実部の整数値 |
| to_f結果 | Float | 虚部が0の場合の実部の浮動小数点値 |
| to_s結果 | String | "real+imaginaryi"形式の文字列 |
| polar結果 | Array | [abs, arg]の2要素配列 |
| rectangular結果 | Array | [real, imaginary]の2要素配列 |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. Complex(real, imag)の呼び出し
   └─ complex_s_rect()で引数を取得（mrb_get_args "f|f"）
2. mrb_complex_new(real, imaginary)で内部生成
   └─ complex_alloc()でRComplex構造体を割り当て
   └─ 実部/虚部をstruct mrb_complexに格納
   └─ frozen = 1 でイミュータブル化
3. Complexオブジェクトを返却
```

### フローチャート

```mermaid
flowchart TD
    A[Complex real, imag] --> B[complex_s_rect: 引数取得]
    B --> C[mrb_complex_new]
    C --> D[complex_alloc: RComplex割り当て]
    D --> E{COMPLEX_INLINE?}
    E -->|Yes| F[インライン配置]
    E -->|No| G[mrb_malloc: ヒープ割り当て]
    F --> H[real/imaginary設定]
    G --> H
    H --> I[frozen = 1]
    I --> J[Complexオブジェクト返却]
```

```mermaid
flowchart TD
    K[Complex除算 a / b] --> L{bの型}
    L -->|実数| M{b == 0?}
    M -->|Yes| N[ZeroDivisionError]
    M -->|No| O[real/b, imag/b]
    L -->|Complex| P{b.real==0 && b.imag==0?}
    P -->|Yes| N
    P -->|No| Q{極端な値?}
    Q -->|Yes| R[frexp/ldexpペア演算]
    Q -->|No| S{|br| > |bi|?}
    S -->|Yes| T[Smithの公式 br基準]
    S -->|No| U[Smithの公式 bi基準]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-60-01 | イミュータブル | Complexオブジェクトは生成後にfrozenとなる | 常時 |
| BR-60-02 | ゼロ除算禁止 | 0(実数)および0+0i(Complex)による除算でZeroDivisionError | 除算時 |
| BR-60-03 | MRB_NO_FLOAT非対応 | MRB_NO_FLOAT設定時はコンパイルエラー | ビルド時 |
| BR-60-04 | 型変換制約 | to_f/to_iは虚部が0の場合のみ変換可能、それ以外はRangeError | 型変換時 |
| BR-60-05 | Mathモジュール依存 | polar, abs, arg等の極座標演算にMath関数（cos, sin, hypot, atan2）を使用 | 極座標演算時 |
| BR-60-06 | new禁止 | Complex.newは未定義化され、Complex.rectangular/rectで生成する | 生成時 |
| BR-60-07 | Numeric#i | 任意の数値にiメソッドを適用してComplex(0, self)を生成可能 | Numeric#i呼び出し時 |

### 計算ロジック

- 加算: (a+bi) + (c+di) = (a+c) + (b+d)i
- 減算: (a+bi) - (c+di) = (a-c) + (b-d)i
- 乗算: (a+bi) * (c+di) = (ac-bd) + (ad+bc)i
- 除算（通常）: Smithの公式を使用し、|br|>|bi|の場合と|bi|>=|br|の場合で分岐して精度を確保
- 除算（極端値）: frexp/ldexpによるペア演算で仮数部/指数部に分解してオーバーフロー回避
- べき乗（実数指数）: |z|^n * (cos(n*arg) + sin(n*arg)i)、ただし|z|=hypot(a,b), arg=atan2(b,a)
- べき乗（Complex指数）: exp((x*log|z|-y*arg) + (x*arg+y*log|z|)i)
- abs: hypot(imaginary, real)
- arg: atan2(imaginary, real)
- conjugate: Complex(real, -imaginary)
- abs2: real*real + imaginary*imaginary
- Float変換: (mrb_float)real（虚部0の場合のみ）

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ZeroDivisionError | 0(整数/浮動小数点)またはComplex(0,0)で除算 | 0以外の値で除算 |
| - | RangeError | 虚部が0でないComplexに対するto_f/to_i | 虚部が0のComplexを使用 |
| - | ArgumentError | 未初期化のComplexオブジェクトへのアクセス（非インライン時） | 正常に生成されたオブジェクトを使用 |
| - | コンパイルエラー | MRB_NO_FLOAT設定時 | MRB_NO_FLOATを無効にする |

### リトライ仕様

リトライ不要。

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

該当なし。

## パフォーマンス要件

- COMPLEX_INLINEマクロにより、構造体サイズが許す場合はインライン配置（ヒープ割り当て回避）
- 32ビットプラットフォームかつ64ビットfloat（MRB_USE_FLOAT32未定義）の場合は非インライン（ポインタ参照）
- 除算はSmithの公式で精度を確保しつつ、極端な値の場合のみfrexp/ldexpペア演算にフォールバック
- 加算・減算・乗算はcomplex_op()関数で統一的に処理し、オペレータをchar引数で切り替え

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

特になし。

## 備考

- MRB_TT_COMPLEX型のオブジェクトとして実装
- Kernel#Complexメソッドはプライベートメソッドとして定義
- NilClass#to_cはComplex(0, 0)を返す
- Numeric#to_cはComplex(self, 0)を返す
- Numeric#iメソッドでComplex(0, self)を生成（ただしComplex#iは未定義化）
- mrblib/complex.rbでpolar, inspect, to_s, +@, -@, <=>, abs, abs2, arg, conjugate, fdiv, polar, rectangular, real?, to_c, to_rの各Rubyメソッドを定義
- mrbgem.rakeでMRB_USE_COMPLEXビルドフラグを定義し、mruby-mathへの依存を宣言

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | complex.c | `mrbgems/mruby-complex/src/complex.c` | struct mrb_complex: 実部/虚部のペア（18-21行目） |
| 1-2 | complex.c | `mrbgems/mruby-complex/src/complex.c` | struct RComplex（インライン版）: COMPLEX_INLINEマクロで直接埋め込み（42-48行目） |
| 1-3 | complex.c | `mrbgems/mruby-complex/src/complex.c` | struct RComplex（非インライン版）: ポインタ参照、32ビット+64ビットfloat時（25-28行目） |
| 1-4 | complex.c | `mrbgems/mruby-complex/src/complex.c` | struct float_pair: 除算の精度確保用（354-357行目） |

**読解のコツ**: COMPLEX_INLINEが定義される条件は「32ビットかつ64ビットfloat」以外の場合である。つまり64ビットプラットフォーム、または32ビットでMRB_USE_FLOAT32の場合はインライン配置される。非インライン時はcomplex_ptr()関数でポインタ経由アクセスし、未初期化チェック（35-37行目）も行う。

#### Step 2: 生成とアクセサを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | complex.c | `mrbgems/mruby-complex/src/complex.c` | complex_alloc(): MRB_TT_COMPLEXの割り当て（52-63行目） |
| 2-2 | complex.c | `mrbgems/mruby-complex/src/complex.c` | mrb_complex_new(): Complex生成+frozen設定（74-85行目） |
| 2-3 | complex.c | `mrbgems/mruby-complex/src/complex.c` | complex_s_rect(): Rubyからの生成メソッド（144-151行目） |
| 2-4 | complex.c | `mrbgems/mruby-complex/src/complex.c` | complex_real()/complex_imaginary(): 属性アクセサ（107-129行目） |

**主要処理フロー**:
- **56行目**: MRB_OBJ_ALLOC(mrb, MRB_TT_COMPLEX, c) でオブジェクト割り当て
- **57-61行目**: インライン時は直接参照、非インライン時はmrb_malloc
- **82行目**: comp->frozen = 1 でイミュータブル化
- **149行目**: mrb_get_args(mrb, "f|f", ...) で実部必須、虚部オプション

#### Step 3: 四則演算とべき乗を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | complex.c | `mrbgems/mruby-complex/src/complex.c` | complex_op(): 加減乗の統一処理（250-279行目） |
| 3-2 | complex.c | `mrbgems/mruby-complex/src/complex.c` | mrb_complex_div(): 除算（frexp/ldexp対応）（395-464行目） |
| 3-3 | complex.c | `mrbgems/mruby-complex/src/complex.c` | complex_pow(): べき乗（525-558行目） |
| 3-4 | complex.c | `mrbgems/mruby-complex/src/complex.c` | add_pair/mul_pair/div_pair: 精度確保用ペア演算（359-393行目） |

**主要処理フロー**:
- **256-268行目**: complex_opはComplex相手なら実部/虚部を取り出し、実数相手ならmrb_as_floatで虚部0として扱う
- **270-277行目**: '+' '-' '*'のswitch-caseで演算を分岐
- **402-416行目**: 除算時のゼロチェック（整数0、float 0.0、Complex(0,0)それぞれ）
- **421行目**: 極端な値の判定条件（fabs(br) < DBL_MIN * fabs(bi) かつ逆も成立）
- **430-450行目**: frexp/ldexpペア演算で仮数部/指数部を分離して計算
- **453-463行目**: Smithの公式による通常の複素数除算
- **538-546行目**: Complex指数のべき乗（log|z|とargを使用）
- **550-557行目**: 実数指数のべき乗（pow + cos/sin）

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | complex.rb | `mrbgems/mruby-complex/mrblib/complex.rb` | polar: Math.cos/sinで極座標から生成（13-15行目） |
| 4-2 | complex.rb | `mrbgems/mruby-complex/mrblib/complex.rb` | inspect/to_s: 文字列表現（27-43行目） |
| 4-3 | complex.rb | `mrbgems/mruby-complex/mrblib/complex.rb` | abs/arg/abs2: 極座標関連（99-131行目） |
| 4-4 | complex.rb | `mrbgems/mruby-complex/mrblib/complex.rb` | conjugate/fdiv/polar/rectangular: ユーティリティ（142-195行目） |
| 4-5 | complex.rb | `mrbgems/mruby-complex/mrblib/complex.rb` | +@/-@/<=>: 単項演算子と比較（53-87行目） |
| 4-6 | complex.rb | `mrbgems/mruby-complex/mrblib/complex.rb` | to_r: RangeErrorチェック付きRational変換（220-223行目） |
| 4-7 | complex.rb | `mrbgems/mruby-complex/mrblib/complex.rb` | Numeric#i/Numeric#to_c: 数値からのComplex変換（237-258行目） |
| 4-8 | complex.c | `mrbgems/mruby-complex/src/complex.c` | ROM entries: メソッドテーブル定義（561-575行目） |
| 4-9 | complex.c | `mrbgems/mruby-complex/src/complex.c` | gem_init: クラス/メソッド登録（577-592行目） |

**主要処理フロー**:
- **581行目**: Complex < Numeric の継承関係定義
- **582行目**: MRB_SET_INSTANCE_TT(comp, MRB_TT_COMPLEX)
- **583行目**: MRB_UNDEF_ALLOCATOR(comp) でアロケータ無効化
- **585行目**: Complex.newを未定義化
- **586-587行目**: Complex.rectangular/rectをクラスメソッドとして登録
- **589行目**: MRB_MT_INIT_ROM でROMエントリからメソッドテーブル初期化
- **591行目**: Kernel#Complexをプライベートメソッドとして登録

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

```
Kernel#Complex(real, imag)  [complex_s_rect]
    |
    +-- mrb_complex_new(mrb, real, imaginary)
         |
         +-- complex_alloc() [RComplex構造体割り当て]
         |    +-- MRB_OBJ_ALLOC(MRB_TT_COMPLEX)
         |    +-- [非インライン] mrb_malloc(sizeof(struct mrb_complex))
         |
         +-- p->real = real, p->imaginary = imaginary
         +-- comp->frozen = 1

Complex#+ / #- / #*
    |
    +-- complex_op(mrb, x, y, op)
         +-- [Complex相手] complex_ptr() で実部/虚部取得
         +-- [実数相手] mrb_as_float() で変換、虚部=0
         +-- '+': (a+c, b+d)
         +-- '-': (a-c, b-d)
         +-- '*': (ac-bd, ad+bc)

Complex#/
    |
    +-- mrb_complex_div(mrb, self, rhs)
         +-- [実数相手] (real/f, imag/f)
         +-- [Complex相手]
              +-- [極端値] frexp/ldexp ペア演算
              |    +-- add_pair(), mul_pair(), div_pair()
              +-- [通常] Smithの公式
                   +-- |br|>|bi|: r=bi/br, den=br+r*bi
                   +-- |bi|>=|br|: r=br/bi, den=bi+r*br

Complex#**
    |
    +-- complex_pow()
         +-- [Complex指数] log|z|+arg -> exp(a)*cos(b), exp(a)*sin(b)
         +-- [実数指数] pow(|z|,n) -> cos(n*arg), sin(n*arg)

Complex.polar(abs, arg)  [Ruby]
    |
    +-- Complex(abs*Math.cos(arg), abs*Math.sin(arg))

Complex#abs  [Ruby]
    +-- Math.hypot(imaginary, real)

Complex#arg  [Ruby]
    +-- Math.atan2(imaginary, real)
```

### データフロー図

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

real (Float)    ──────────> mrb_complex_new()  ──────────> Complex (frozen)
imag (Float)    ──────────>   |                              (real/imaginary)
                              +-- complex_alloc
                              +-- frozen設定

Complex + Complex ─────────> complex_op('+')  ──────────> Complex (新規)
                              +-- (a+c, b+d)

Complex * Complex ─────────> complex_op('*')  ──────────> Complex (新規)
                              +-- (ac-bd, ad+bc)

Complex / Complex ─────────> mrb_complex_div()  ────────> Complex (新規)
                              +-- ゼロ除算チェック
                              +-- Smithの公式 or ペア演算

Complex ** n    ──────────> complex_pow()  ──────────────> Complex (新規)
                              +-- polar形式で計算
                              +-- exp/cos/sin

Complex#to_f   ──────────> mrb_complex_to_f()  ────────> Float
                              +-- 虚部0チェック
                              +-- RangeError or real返却
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| complex.c | `mrbgems/mruby-complex/src/complex.c` | ソース | Complexクラスの主要C実装（598行） |
| complex.rb | `mrbgems/mruby-complex/mrblib/complex.rb` | ソース | polar/inspect/to_s/abs/arg/conjugate等のRuby実装（259行） |
| complex.rb | `mrbgems/mruby-complex/test/complex.rb` | テスト | Complexクラスの動作テスト（175行） |
| mrbgem.rake | `mrbgems/mruby-complex/mrbgem.rake` | 設定 | gemメタデータ定義、MRB_USE_COMPLEXフラグ、mruby-math依存 |
