Groovy で複素数の計算処理を実装する。
最終更新:2014/09/06
calc.groovy 複素数の計算式を処理するスクリプト
// calc.groovy
// Version 1.0
// KAKU PROJECT (2014)
// 概要:複素数の計算式を処理するスクリプト
// 実行例: groovy calc.groovy file
// ビルトイン定数とビルトイン関数の定義
def binding = new Binding([
// i: 虚数
i: new Complex(0, 1),
// Re: 複素数から実数部を取り出す関数
Re: {z -> z.r},
// Im: 複素数から虚数部を取り出す関数
Im: {z -> z.i},
// conjugate: 複素数の共役複素数を作る関数
conjugate: {z ->
def z2 = new Complex(z)
new Complex(z2.r, -z2.i)},
// conjugate: 複素数の絶対値を計算する関数
abs: {z ->
def z2 = new Complex(z)
java.lang.Math.sqrt(z2.r**2 + z2.i**2)}
])
// Number クラスに複素数オブジェクト用の演算を追加する。
// 加算
Number.metaClass.plus = {Complex b ->
new Complex (delegate, 0)+b
}
// 減算
Number.metaClass.minus = {Complex b ->
new Complex (delegate, 0)-b
}
// 乗算
Number.metaClass.multiply = {Complex b ->
new Complex (delegate * b.r, delegate * b.i)
}
// 除算
Number.metaClass.div = {Complex b ->
new Complex (delegate, 0)/b
}
// 入力ファイルの各行の式を加工し、ストリングバッファに保存。
def sb = new StringBuffer()
new File(args[0]).eachLine {
sb << "println (\"${it}\\n==>\${${it}}\\n\")\n"
// println sb
}
// メモ:
// 入力行→xxx
// 評価される行→println ("xxx\n==>${xxx}\n")
// エスケープした行→"println (\"xxx\\n==>\${xxx}\\n\")\n"
// 式の評価。
def shell = new GroovyShell(binding)
shell.evaluate(
sb.toString()
)
Complex.groovy
複素数のクラス。
// Complex.groovy
// Version 1.0
// KAKU PROJECT (2014)
// 概要:複素数を表現するクラス
public class Complex
{
// ○複素数の実数部・虚数部プロパティ
// ・実数部
private Number r = 0
// ・虚数部
private Number i = 0
// メモ:実数部・虚数部の値は Number クラスにしておくことで、任意の数値クラス
// (Integer,Long,Double,float,BigDecimal)を使えるようにする。
// ・実数部の参照メソッド
public Number getR () {r}
// ・虚数部の参照メソッド
public Number getI () {i}
// メモ:変更メソッド(setR, setI) は用意しない。
// ○コンストラクタ
// ・実数部のみの複素数
public Complex (Number r) {
this.r = r
this.i = 0
}
// ・実数部+虚数部からなる複素数
public Complex (Number r, Number i) {
this.r = r
this.i = i
}
// 既存の複素数オブジェクト用コンストラクタ
public Complex (Complex z) {
this.r = z.r
this.i = z.i
}
// ○演算子用メソッド。
// メモ:各演算子の結果は常に新しいオブジェクトを作成し、既存のオブジェクトは
// 変化させないこととする。++ や -- などの単項演算子は用意しない。
// ・加算(二項演算・引数:複素数)
public Complex plus(Complex b) {
new Complex(r+b.r, i+b.i)
}
// ・加算(二項演算・引数:実数)
public Complex plus(Number n) {
new Complex(r+n, i)
}
// ・減算(二項演算・引数:複素数)
public Complex minus (Complex b) {
new Complex(r-b.r, i-b.i)
}
// ・減算(二項演算・引数:実数)
public Complex minus(Number n) {
new Complex(r-n, i)
}
// ・乗算(二項演算・引数:複素数)
public Complex multiply (Complex b) {
new Complex((r*b.r)-(i*b.i), (r*b.i)+(i*b.r))
}
// ・乗算(二項演算・引数:実数)
public Complex multiply(Number n) {
new Complex(r*n, i*n)
}
// ・除算(二項演算・引数:複素数)
public Complex div (Complex b) {
if (b.isZero()) {
// ゼロ除算例外
throw new java.lang.ArithmeticException("Division by zero")
}
if (this.equals(b)) {
// 同じ複素数なら1を返す。
return new Complex(1, 0)
}
double t = b.r*b.r + b.i*b.i
new Complex(
(r*b.r+i*b.i)/t,
(i*b.r-r*b.i)/t)
}
// ・除算(二項演算・引数:実数)
public Complex div (Number n) {
if (n == 0) {
// ゼロ除算例外
throw new java.lang.ArithmeticException("Division by zero")
}
new Complex(r/n, i/n)
}
// ・累乗(二項演算・引数:整数)
public Complex power (int n) {
//println "n:$n"
Complex z = this
if (n < 0) {
z = new Complex(1, 0).div(this.power(-n))
} else if (n == 0) {
z = new Complex(1, 0)
} else {
z = this
for (int i=1; i<n; i++) {
//println "i:$i"
z = z.multiply(this)
//println "z:$z"
}
}
z
}
// ・マイナス(単項演算)
public Complex negative () {
new Complex(-r, -i)
}
// ・プラス(単項演算)
public Complex positive () {
this
}
// ・比較(二項演算・引数:複素数)
public boolean equals (Complex b) {
this.r == b.r && this.i == b.i
}
// ・補助メソッド。0 か否かを調べる
public boolean isZero () {
this.r == 0 && this.i == 0
}
// 文字列化(toString)
// ・補助メソッド。虚数部の文字列化。プラス符号なし。
private String toImgString2 () {
if (i == 0) {
""
} else if (i == 1) {
"i"
} else if (i == -1) {
"-i"
} else if (i < 0) {
"-${i*(-1)}i"
} else {
"${i}i"
}
}
// ・補助メソッド。虚数部の文字列化。プラス符号あり。
private String toImgString1 () {
if (i == 0) {
""
} else if (i == 1) {
"+i"
} else if (i == -1) {
"-i"
} else if (i < 0) {
"-${(double)i*(-1)}i"
} else {
"+${(double)i}i"
}
}
// ・複素数の文字列化
public String toString () {
if (i == 0) {
if (r == 0) {
"0"
} else {
"${(double)r}"
}
} else {
if (r == 0) {
toImgString2()
} else {
"${(double)r}${toImgString1()}"
}
}
}
} // End of class Complex
複素数の計算式のファイル例。
3+4*i 4.0+3.0*i (3+4*i)*(4.0+3.0*i) (3+4*i)*(4.0+3.0*i)*i (3+4*i)/(4.0+3.0*i) (0.96+0.28*i)*(4.0+3.0*i)実行例
C:\work\complex>groovy calc.groovy z.txt 3+4*i ==>3.0+4.0i 4.0+3.0*i ==>4.0+3.0i (3+4*i)*(4.0+3.0*i) ==>25.0i (3+4*i)*(4.0+3.0*i)*i ==>-25.0 (3+4*i)/(4.0+3.0*i) ==>0.96+0.28i (0.96+0.28*i)*(4.0+3.0*i) ==>3.0+4.0i
●メモ。演算子のオーバーロードについて。
(0.96+0.28*i)*(4.0+3.0*i)の式において、各演算子は次のように展開される:
(0.96.plus(0.28.multiply(i)).multiply(4.0.plus(3.0.multiply(i)))この際に各演算子の優先順位は Groovy の処理系が決定する。 例えば、0.96 への plus メソッドの適用時には、calc.groovy の 27~28 で Number クラスに追加したメソッドが使われる。 また、"i" は calc.groovy の 10 行目で定義されたビルトイン定数が使われる。
![]() |
KAKU PROJECT (2014) |