Rubyの複素数ライブラリのソースコードを読む

昨日のエントリで、Ruby複素数クラスを定義した。でも標準でComplex(複素数)クラスはある。なので、今度はそのソースコードを読んでみることにした。

複素数ライブラリのソースファイルは、僕の環境(Ubuntu 8.04)では /usr/lib/ruby/1.8/complex.rb にあった。あと、Google Code Seach でも見つかった

全体の構成

ファイル全体の基本的な構成は以下の通り。

# 組み込みのNumericクラスに定義を追加する
class Numeric
  # ...
end

# 新しいComplexオブジェクトを作成するメソッドを定義する
def Complex(a, b = 0)
  # ...
end

# 複素数クラスを新たに定義する
# これがメイン
class Complex < Numeric
  # ...
end

# Mathモジュールに定義を追加する
module Math
  # ...
end

1ファイル1クラスというわけではなくて、何か色々やってる。

Complexクラスを読む

とりあえずメインとなるComplexクラスを読んでみる。ふむふむ。足し算、かけ算とかが定義されている。けっこう普通だけど、複素数同士だけでなく複素数 + 整数 とかでも大丈夫なようにしてある。あと、何かFIXMEって書いてあったけど気にしない。

ComplexクラスはNumericクラスを継承しているので、Numericクラスのリファレンスを見てみる。

数値を表す抽象クラスです。

http://doc.okkez.net/186/view/class/Numeric

そりゃそうだ。

演算や比較を行うメソッド(+, -, *, /, <=>)は Numeric のサブクラスで定義されます。Numeric で定義されているメソッドは、サブクラスで提供されているメソッド (+, -, *, /, %) を利用して定義されるものがほとんどです。

http://doc.okkez.net/186/view/class/Numeric

確かにそうなってる。

つまり Numeric で定義されているメソッドは、Numeric のサブクラスとして新たに数値クラスを定義した時に、演算メソッド(+, -, *, /, %, <=>, coerce)だけを定義すれば、数値クラスのそのほかのメソッドが適切に定義されることを意図して提供されています。

http://doc.okkez.net/186/view/class/Numeric

おお、そりゃ便利だ。コードと照らし合わせるとドキュメントの意味も分かりやすい。

Numericクラスを読む

次にNumericクラスに定義を追加してる所を読んでみる。お、ここは量が少ないぞ。ふむふむ。real (実部), image (虚部), arg (偏角)とか追加してる。というか、さっき読んだNumericクラスのリファレンスの一番下に書いてある。なるほど。このcomplexをrequireするとNumericが複素数対応になるのか。

Complexメソッドを読む

次にComplexメソッドの所を読んでみる。ここは短い(5行)。要するにComplex.new(a, b) の代わりに Complex(a, b) でもOKになってる。

Mathモジュールを読む

ここではsin, cosとかを複素数に対応させている。Mathモジュールのリファレンスを見てもそれっぽいことが書いてある。うむ、ドキュメント通りだ。

あと、ここでいくつか気になったことがあった。

  • alias

こんな感じでaliasを使ってる。

alias exp! exp

def exp(z)
  if Complex.generic?(z)
    exp!(z)  # ここで元のexpを使う
  else
    Complex(exp!(z.real) * cos!(z.image), exp!(z.real) * sin!(z.image))
  end
end

つまり、複素数対応する前の元のメソッドを ! 付きの名前で待避させておいて、必要に応じてそれを呼び出してる。たぶん、メソッドを拡張させるときのお決まりのパターンなんだろう。

  • module_function

一番最後にメソッドをmodule_functionにしてる。

module_function :exp!
module_function :exp

僕が読んでる 初めてのRuby には載ってないし、いまいちよく分からない。まああれか、Math.exp って形式で呼べるってことか。

最後に

うん、さすがにちゃんと作ってある(そりゃそうだ)。あと、思ったより分かりやすかった。5 ~ 10行ぐらいのメソッドが多いし、読みやすい。こうやってソースコードを直接読めるのがオープンソースの良い所だね。