倭算数理研究所

科学・数学・学習関連の記事を、「倭マン日記」とは別に書いていくのだ!

倭マン's Math (6) : BigRealField, BigReal (org.apache.commons.math. パッケージ)

今回は実数体と実数を表す BigRealField, BigReal クラスにメソッド(クロージャ型のプロパティ)を追加していきます(一覧)。 ちなみに前回に追加した FieldElement へのメソッドも使用できます(サンプルにいくつか載せてますが)。

インスタンス生成


まずはインスタンスの生成方法。 数字リテラル、文字列リテラルから bigReal() メソッドによって対応する BigReal オブジェクトを取得できるようにしてます:

@GrabResolver('http://www5.ocn.ne.jp/~coast/repo/')
@Grab('org.waman.math:wamans-math:0.0.1')

WamansMath.enhance(CommonsMathPackage.UTIL)

// int / Integer からの生成
def r1 = 1.bigReal()

// doubel / Double からの生成
def r2 = 2.0d.bigReal()

// BigDecimal からの生成
def r3 = 3.0.bigReal()

// String からの生成
def r4 = '4'.bigReal()

// GString からの生成
def r5 = "5".bigReal()

コンストラクタから生成するのより楽なような、変わらないような、ですけど。

メソッド使用サンプル


次はメソッドの使い方。 演算子に対応するメソッドが主です。 FieldElement に追加したメソッド (plus(), minus(), div() など。 演算子では +, -, /) も使用できます:

@GrabResolver('http://www5.ocn.ne.jp/~coast/repo/')
@Grab('org.waman.math:wamans-math:0.0.1')

WamansMath.enhance(CommonsMathPackage.UTIL)

def r1 = 1.bigReal()
def r2 = 2.bigReal()
def r3 = 3.bigReal()
def r_1 = -1.bigReal()

// -1 (積演算の単位元 1 の和演算に関する逆元)
assert BigRealField.instance.getMinusOne() == -1.bigReal()
assert BigReal.MINUS_ONE == -1.bigReal()

// 単位元であるかどうかの評価メソッド
assert r1.isOne()
assert !r2.isZero()
assert r_1.isMinusOne()

// 符号など
assert +r2 == r2
assert -r2 == -2.bigReal()
assert ~r2 == 0.5.bigReal()    // ~ (bitwiseNegate()) は逆数を返すようにしてます

// 1 の増減 previous() / next()
assert ++r2 == 3.bigReal()
assert --r2 == 2.bigReal()

// 四則演算と冪乗
assert r2 + r3 == 5.bigReal()
assert r2 - r3 == -1.bigReal()
assert r2 * r3 == 6.bigReal()
assert r3 / r2 == 1.5.bigReal()
assert r2**3 == 8.bigReal()

// 型変換
assert (r2 as BigDecimal) instanceof BigDecimal
assert (r2 as double) instanceof Double
assert (r2 as String) instanceof String

// BigReal に定義されてないメソッドは bigDecimalValue() に処理を委譲 : methodMissing
assert r_1.abs() == 1.bigReal()

BigReal に定義されていないけど BigDecimal に定義されているメソッド(サンプルでは最後の abs() メソッド)は、BigDecimal オブジェクトに処理を委譲した後に返り値を BigReal オブジェクトに変換するようにしてあります(ちょっと雑な実装ですけど)。

メソッドの追加スクリプト


特に詳細を気にする必要はありませんが、メソッドを追加するスクリプトはこんな感じ:

        // -1 の追加
        def _1 = new BigReal(-1d)
        BigRealField.metaClass.getMinusOne = { -> _1 }
        BigReal.metaClass.'static'.getMINUS_ONE = { -> _1 }

        // メソッド追加 (主に演算子オーバーライド)
        BigReal.metaClass.define{
            isMinusOne = { -> delegate == _1 }
            negative = { -> new BigReal((BigDecimal)bigDecimalValue().negate()) }
            previous = { -> delegate.subtract(BigReal.ONE) }
            next = { -> delegate.add(BigReal.ONE) }
            bitwiseNegate = { -> BigReal.ONE.divide((BigReal)delegate)}
            power = { int n -> new BigReal((BigDecimal)bigDecimalValue().pow(n)) }

            // as キーワードによる型変換
            asType = { Class type ->
                switch(type){
                    case BigReal.class:
                        return delegate
                    case BigDecimal.class:
                        return bigDecimalValue()
                    case double.class:
                        return doubleValue()
                    case Double.class:
                        return Double.valueOf((double)doubleValue())
                    case String.class:
                        return bigDecimalValue().toPlainString()
                }
            }

            // BigReal にないメソッドは BigReal#bigDecimalValue() で得られる BigDecimal オブジェクトへ処理を委譲
            // 返り値が BigDecimal オブジェクトなら BigReal オブジェクトに変換して返す
            methodMissing = { String name, args ->
                def result = bigDecimalValue().invokeMethod(name, args)
                if(result instanceof BigDecimal)
                    return new BigReal(result)
                else
                    return result
            }
        }

        // Number オブジェクトから BigReal オブジェクトを生成
        Number.metaClass.bigReal = { MathContext context = null ->
            switch(getClass()){
                case BigDecimal.class:
                case BigInteger.class:
                    return (context != null) ? new BigReal(delegate, context) : new BigReal(delegate)
                default:
                    return (context != null) ? new BigReal(doubleValue(), context) : new BigReal(doubleValue())
            }
        }

        // String オブジェクトから BigReal オブジェクトを生成
        String.metaClass.bigReal = { MathContext context = null ->
            return (context != null) ? new BigReal(delegate, context) : new BigReal(delegate)
        }

Javaによるアルゴリズム事典

Javaによるアルゴリズム事典