今回は有理数体を表す FractionField クラスと、その体の元で分数(有理数)を表す Fraction クラスにメソッドを追加していきます。
インスタンス生成
まずは Fraction オブジェクトのインスタンス生成。 (int の)配列や String, Number オブジェクトに追加した frac() メソッドや Integer に追加した over() メソッドで簡単にインスタンスが生成できます:@GrabResolver('http://www5.ocn.ne.jp/~coast/repo/') @Grab('org.waman.math:wamans-math:0.0.1') WamansMath.enhance(CommonsMathPackage.FRACTION) // int / Integer の配列からインスタンス生成 assert [1, 2].frac() == new Fraction(1, 2) // int の over() メソッドからインスタンス生成 assert 1.over(2) == [1, 2].frac() // String / GString からインスタンス生成 assert '1 / 3'.frac() == [1, 3].frac() assert "1 / 4".frac() == [1, 4].frac() // Number オブジェクトの List からインスタンス生成 assert [2].frac() == [2, 1].frac() assert [3d].frac() == [3, 1].frac() assert [0.33333333333333333d, 10].frac() == [1, 3].frac() assert [0.33333333333333333d, 0.01d, 10].frac() == [1, 3].frac()
Number オブジェクトの List に対して frac() メソッドを呼び出すと、各オブジェクトの型に対応した Fraction クラスのコンストラクタが呼び出されます。
メソッドの使用サンプル
次は単項演算と2項演算。 基本的に演算子オーバーロードに関連するメソッドを追加しています:@GrabResolver('http://www5.ocn.ne.jp/~coast/repo/') @Grab('org.waman.math:wamans-math:0.0.1') WamansMath.enhance(CommonsMathPackage.FRACTION) assert FractionField.instance.getMinusOne() == Fraction.MINUS_ONE def f12 = [1, 2].frac() def f13 = [1, 3].frac() // 単項演算 assert +f12 == [1, 2].frac() assert -f12 == [-1, 2].frac() assert ~f12 == 2.frac() // ~(bitwiseNegate) は逆数を返すようにしてます。 // Fraction 同士の2項演算 assert f12 + f13 == [5, 6].frac() assert f12 - f13 == [1, 6].frac() assert f12 * f13 == [1, 6].frac() assert f12 / f13 == [3, 2].frac() // Fraction と int / Integer との2項演算 assert f12 + 1 == [3, 2].frac() assert f12 - 1 == [-1, 2].frac() assert f12 * 3 == [3, 2].frac() assert f12 / 2 == [1, 4].frac() assert f12 ** 2 == [1, 4].frac() // int / Integer と Fraction との2項演算 assert 1 + f12 == [3, 2].frac() assert 1 - f12 == [1, 2].frac() assert 3 * f12 == [3, 2].frac() assert 2 / f12 == 4.frac()
「分数+分数」、「分数+整数」だけでなく、「整数+分数」の計算もできます(実は「double + 分数」もできます)。
フォーマット
最後はフォーマット。 FractionFormat#parse() の機能を、FractionFormat オブジェクトを生成せずに使用できるようにしてます:@GrabResolver('http://www5.ocn.ne.jp/~coast/repo/') @Grab('org.waman.math:wamans-math:0.0.1') WamansMath.enhance(CommonsMathPackage.FRACTION) // 文字列から Fraction オブジェクトを読み込む assert Fraction.parse('1 / 3') == [1, 3].frac()
ロケールなどの詳細を設定したい場合はこのメソッドを使えないので、通常の FractionFormat オブジェクトを使用してください。
メソッド追加スクリプト
最後に Groovy のメタクラスを使ったメソッド追加スクリプト。 例によって詳細はあまり気にせずに。// FractionField へのメソッド追加 FractionField.metaClass.getMinusOne = { -> Fraction.MINUS_ONE } // Fraction へのメソッド追加 Fraction.metaClass.define{ isMinusOne = { -> delegate == _1 } // 単項演算 negative = { -> negate() } bitwiseNegate = { -> reciprocal() } previous = { -> delegate.subtract(Fraction.ONE) } next = { -> delegate.add(Fraction.ONE) } // 2項演算 div = { Fraction arg -> divide(arg) } plus = { int arg -> add(arg) } minus = { int arg -> subtract(arg) } div = { int arg -> divide(arg) } power = { int n -> return new Fraction( MathUtils.pow((int)getNumerator(), n), MathUtils.pow((int)getDenominator(), n)) } plus = { double arg -> add(new Fraction(arg)) } minus = { double arg -> subtract(new Fraction(arg)) } multiply = { double arg -> multiply(new Fraction(arg)) } div = { double arg -> divide(new Fraction(arg)) } // 型変換 asType = { Class type -> switch(type){ case Fraction: return delegate case double: return doubleValue() case Double: return Double.valueOf((double)doubleValue()) case String: return toString() } } } // Fraction へのメソッド追加(static メソッド) def format = new FractionFormat() Fraction.metaClass.'static'.parse = { String arg -> format.parse(arg) }
Fraction, FractionField クラスへのメソッド追加はこんな感じですが、これだけだと「分数 + 整数」の計算はできても「整数+分数」の計算ができないので、Integer クラスにもメソッド追加をして「整数+分数」の計算もできるようにしましょう(Double にも同様のメソッドを追加しています)。 また、Integer, Double, String, List に frac() メソッドを追加して、Fraction オブジェクトを簡単に生成できるようにもしておきます:
// int / Integer, double / Double との演算 [Integer.metaClass, Double.metaClass].each{ mc -> mc.define{ frac = { -> new Fraction(delegate)} plus = { Fraction arg -> frac().add(arg) } minus = { Fraction arg -> frac().subtract(arg) } multiply = { Fraction arg -> frac().multiply(arg) } div = { Fraction arg -> frac().divide(arg) } } } Integer.metaClass.over = { int i -> new Fraction((int)delegate, i) } String.metaClass.frac = { -> format.parse((String)delegate) } List.metaClass.frac = { -> new Fraction(*delegate) }
- 作者: 奥村晴彦,杉浦方紀,津留和生,首藤一幸,土村展之
- 出版社/メーカー: 技術評論社
- 発売日: 2003/05
- メディア: 単行本
- 購入: 2人 クリック: 61回
- この商品を含むブログ (61件) を見る
数学ガール フェルマーの最終定理 (数学ガールシリーズ 2)
- 作者: 結城浩
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2008/07/30
- メディア: ペーパーバック
- 購入: 35人 クリック: 441回
- この商品を含むブログ (260件) を見る