今回は連分数を表す org.apache.commons.math.util.ContinuedFraction クラスを見ていきます。
連分数
連分数の詳細に関してはこちらやwikipedia:連分数などを参照のこと。 後でサンプルに用いるため、1つだけ連分数の具体例を見ておきます(参照):これは書くのも見るのも面倒なので、こんな感じに書かれることもあります:
まぁ、どっちもどっちかな。 一般に連分数は
として、{an}, {bn} を定めれば決まります。
ちなみに、この ContinuedFraction クラスは org.apache.commons.math.fraction パッケージの Fraction クラスや BigFraction クラスとは何の関係もないようです。
ContinuedFraction クラス
さて、では ContinuedFraction クラスを見ていきましょう。 使い方の手順はこんな感じ:- ContinuedFraction のサブクラスを作成する
- ContinuedFraction オブジェクトを取得する
- ConitnuedFraction#evalueate() メソッドによって(必要な精度で)値を取得する
もしくは
- CotinuedFraction の無名クラスを作成して ContinuedFraction オブジェクトを取得する
- ConitnuedFraction#evalueate() メソッドによって(必要な精度で)値を取得する
まぁ、要は ContinuedFraction クラスは抽象クラスだよ?ってだけです。 実装する必要がある抽象メソッドは以下の2つ:
protected abstract double getA(int n, double x); protected abstract double getB(int n, double x);
これらは上記の例の下に書いた一般形の {an}, {bn} を計算するメソッドで、x は次に見る評価点です(上記のπの例では評価点に依存しない)。 精度を指定して値を評価する evaluate() メソッドはいくつかオーバーロードされてます:
public double evaluate(double x){ ... } public double evaluate(double x, double epsilon){ ... } public double evaluate(double x, int maxIterations){ ... } public double evaluate(double x, double epsilon, int maxIteration){ ... }
- x は評価点です。 この変数 x は「実行時に指定できるが、全評価段階で一定」の値です。 getA(), getB() メソッドの第2引数の double 型パラメータはこの値が渡されます。 ちなみに、getA(), getB() メソッド第1引数の n は「実行時には指定できないが、各評価段階で変化する」値です。 使い分けられれば柔軟性が増しそう。
- epsilon は前回みたdouble 値に対する equals() メソッドの、精度を指定する double 型の第3引数と同じでしょう。
- maxIterations は計算する(最大の) convergent を指定する整数です。 まぁ分数の繰り返し回数と思ってもいいかと。 詳しくはこちら(「convergent」で検索してちょ)。
実行してみる
やっぱ、こういうのは実行してみないとね。 ってことで、次の3つの方法で上記 の連分数を計算してみました:Pure Java
まずは Java オンリーの実装:import org.apache.commons.math.util.ContinuedFraction; public class Pi extends ContinuedFraction{ @Override protected double getA(int n, double x) { return n == 0 ? 3 : 6; } @Override protected double getB(int n, double x) { double y = (2 * n) - 1; return y * y; } }
getA(), getB() メソッドの実装はこんなんだって示すためのサンプルと言ってもいいかも。 実行は後でまとめて。
Groovy Closure
次は Groovy のクロージャを使った実装。 groovy.lang.Closure は使ってますが、このクラス自体は Java で実装してます:import groovy.lang.Closure; import org.apache.commons.math.util.ContinuedFraction; public class ClosureContinuedFraction extends ContinuedFraction{ private final Closure a; private final Closure b; public ClosureContinuedFraction(Closure a, Closure b){ this.a = a; this.b = b; } @Override protected double getA(int i, double v) { return (Double)this.a.call(new Object[]{i, v}); } @Override protected double getB(int i, double v) { return (Double)this.b.call(new Object[]{i, v}); } }
クロージャ・プロパティを final 宣言する必要はないかもね*1。 少々パフォーマンスは良くなるかも知れないけど (←あまりパフォーマンスに影響なし。) このクラスは Groovy コード内でこんな感じに使います:
def a = { int n, double x -> return (n == 0) ? 3d : 6d } def b = { int n, double x -> double y = (2d * n) - 1d return y * y } def cfClosure = new ClosureContinuedFraction(a, b)
Groovy Anonymous
最後は Groovy コード内での無名クラス:def cfAnonymous = new ContinuedFraction(){ @Override protected double getA(int n, double x) { return (n == 0) ? 3d : 6d } @Override protected double getB(int n, double x) { double y = (2d * n) - 1d return y * y } }
まぁ、何てことないですね。
パフォーマンス
さて、上記の3つの ContinuedFraction クラスを実行してみましょう。 実行するコードはこんな Groovy コード:perform(new Pi(), 'Pure Java') perform(cfClosure, 'Groovy Closure') perform(cfAnonymous, 'Groovy Anonymous') def perform(cf, message){ def epsilon = 0.0000001d def start = System.currentTimeMillis() 10000.times{ cf.evaluate(0d, epsilon) } def end = System.currentTimeMillis() println("$message : ${end - start} ms") }
cfClosure はクロージャによる実装、cfAnonymous は無名クラスによる実装。 精度を指定して 10000 回評価を行っています。 結果は
Pure Java : 125 ms
Groovy Closure : 2906 ms
Groovy Anonymous : 1000 ms
うーむ、クロージャを使うと Pure Java の20倍以上になっとる。 無名クラスだとかろうじて10倍にならずに済んだってところ。 まぁ、1回1msもかかってないから気にする程でもないのか・・・
追記
クロージャを値に持つ Map を使って[getA:a, getB:b] as ContinuedFraction // a, b はクロージャ
のように ContinuedFraction オブジェクトを作成することもできます。 これを以下のように実行すると
def a = { int n, double x -> return (n == 0) ? 3d : 6d } def b = { int n, double x -> double y = (2d * n) - 1d return y*y } perform([getA:a, getB:b] as ContinuedFraction, 'Groovy Closure Map')
実行にかかった時間は Pure Java の50倍! さすがに使うのに抵抗が。
- 作者: 奥村晴彦,杉浦方紀,津留和生,首藤一幸,土村展之
- 出版社/メーカー: 技術評論社
- 発売日: 2003/05
- メディア: 単行本
- 購入: 2人 クリック: 61回
- この商品を含むブログ (61件) を見る
Mathematica® in Action: Problem Solving Through Visualization and Computation
- 作者: Stan Wagon
- 出版社/メーカー: Springer
- 発売日: 2010/07/12
- メディア: ペーパーバック
- この商品を含むブログ (2件) を見る
Mathematica Cookbook (Cookbooks (O'Reilly))
- 作者: Salvatore Mangano
- 出版社/メーカー: Oreilly & Associates Inc
- 発売日: 2010/04
- メディア: ペーパーバック
- 購入: 1人 クリック: 18回
- この商品を含むブログ (2件) を見る