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
って形式で呼べるってことか。