オブジェクト指向 複素数クラス

目次 解答例(ないかも)

締切は 2002/07/05. お薦め課題 なし.

課題10_01 オブジェクト指向 複素数クラス

宇土先生の本 p121 演習 10.1 に, 複素数を表す構造体をつくろう! というものがあります. 樋口が考えた解答は下のようなものです.

complex.hへッダーファイル
complex.cプログラム本体
complextest.c使い方サンプル
コンパイルの方法は, cc -o complextest complex.c complextest.c -lm.

これを, Java でそのまま書き直すと, 次のようになります.

Complex.javaクラスファイル
ComplexTest1.java使い方サンプル
同じディレクトリに保存して, ComplexTest1.javaをコンパイル, 実行すればよい.

オブジェクト指向っぽく書き直す試みが下です.

/** 
    議論はわかれると思うが, Java でありそうな Complex クラスの実装
    2002/06/17 Mon 20:27 hig
 */

class Complex {
    /**実部*/
    private double realPart; /* private は, クラス外から直接にアクセス
                                できないことを示す. getReal() を使う */
    /**虚部*/
    private double imagPart;

    /** いわばcompset に対応. コンストラクタという */
    Complex(double x, double y){
	this.realPart=x;	/* this はオブジェクト自身を指す*/
	this.imagPart=y;
    }

    /** 実部だけを持つ場合のコンストラクタ */
    Complex(double x){
	this.realPart=x;
	this.imagPart=0;
    }

    /** デフォルトコンストラクタ */
    Complex(){
    }

    /** 実部を返すメソッド */
    public double getReal(){
	return realPart;	// this.realPart と書いても同じ.
    }

    /** 虚部を返すメソッド */
    public double getImag(){
	return imagPart;
    }

    /** 自分自身 z と 引数 z2 との和 z+z2 を返すメソッド. 自分を変更しない */
    public Complex add( Complex z2){
	return new Complex( this.realPart+z2.realPart, this.imagPart+z2.imagPart);
    }
  
    /** 自分自身 z と 引数 z2 との差 z-z2 を返すメソッド. 自分を変更しない */  
    public  Complex subtract( Complex z2){
	/* 埋めてね ****************************************************/
    }

    /** 自分自身 z と 引数 z2 との積 z*z2 を返すメソッド. 自分を変更しない */  
    public  Complex multiply(Complex z2){
	/* 埋めてね *****************************************************/
    }

    /** 自分自身 z と 引数 z2 との商 z/z2 を返すメソッド. 自分を変更しない */  
    public  Complex divide(Complex z2){
	double bunbo=z2.getAbs();

	if( bunbo==0.0 ){
	    System.err.println("Complex.divide: 0 による除算");
	    /* 本当は, Java では "例外を投げる" のが正しい */
	    return this;
	}
	
	return this.multiply( z2.getConjugate() ).multiply( new Complex(1.0/bunbo/bunbo));
    }

    /** 自分自身 z の複素共役 bar z を返すメソッド. 自分を変更しない */  
    public Complex getConjugate(){
	return new Complex(realPart,-imagPart); 
	//	   this.realPart の this は省略できる.
    }

    /** 自分自身 z の絶対値 |z| を返すメソッド. 自分を変更しない */  
    public  double getAbs(){
	/* 埋めてね ****************************************************/
    }

    /** 自分自身 z の偏角 arg z を返すメソッド. 自分を変更しない */  


    public  double getArg(){
	double arg;

	if ( imagPart < 0 ){
	    arg=( new Complex(-realPart,-imagPart) ).getArg();
	} else if ( imagPart==0.0 ){
	    if ( realPart > 0 ){
		arg=0.0;
	    } else if ( realPart < 0.0 ){
		arg=Math.PI;
	    } else {		/* z=0 */
		arg=0.0;
		System.exit(99);
	    /* 本当は, Java では "例外を投げる" のが正しい */
	    }
	} else {
	    if( realPart==0.0 ){
		arg=Math.PI/2.0;
	    } else {
		arg=Math.atan(imagPart/realPart);
	    }
	}

	return arg;
    }

    /* 
	print は改めては定義しない. 
	String (文字列) への変換方法を与えておけば十分
    */
    /** 自分自身を表す文字列を返すメソッド */
    public  String toString(){
	return "(" + realPart + "," + imagPart +")";

    }

    /** 自分自身 z と 引数 z2 が等しいかを boolean で返すメソッド*/
    public boolean equals(Complex z2){
	return (this.realPart==z2.realPart && this.imagPart==z2.imagPart) ;
    }



    /* 以下は static 版. 併用できる. */

    public static Complex set( double x, double y){
	return new Complex(x,y);
    }

    public static Complex add( Complex z1, Complex z2){
	return new Complex( z1.realPart+z2.realPart, z1.imagPart+z2.imagPart);
    }
  
  
    public static Complex sub( Complex z1, Complex z2){
	return new Complex( z1.realPart-z2.realPart, z1.imagPart-z2.imagPart);
    }


    public static Complex mult(Complex z1, Complex z2){
	return new Complex(z1.realPart*z2.realPart - z1.imagPart*z2.imagPart,
			   z1.imagPart*z2.realPart + z1.realPart*z2.imagPart);
    }

    public static Complex div(Complex z1, Complex z2){
	double bunbo=z2.getAbs();

	if( bunbo==0.0 ){
	    System.exit(99);
	    /* 本当は, Java では "例外を投げる" のが正しい */
	}
	
	return new Complex((z1.realPart*z2.realPart + z1.imagPart*z2.imagPart)/bunbo,
			   (z1.imagPart*z2.realPart - z1.realPart*z2.imagPart)/bunbo);
    }


    public static double abs(Complex z){
	return z.getAbs();
    }


    public static void print(Complex z){
	System.out.println("(" + z.realPart + ") (" + z.imagPart +")");
    }


    

}


/*
  Local Variables:
  mode: java
  compile-command: "javac -deprecation Sample10_01.java"
  End:
*/

      
Complex.java として保存し, 埋めてね部分を埋めて, 差, 積, 絶対値を返すメソッドを完成させよう. 完成したら, 次のようなプログラムから使おう.
/** 
    もうひとつの Complex クラスのテストのためのプログラム
    全く書き直す必要なし.
*/
class Sample10_01 {

    /** メインメソッド. これが実行される */
    public static void main(String [] args){

	Complex z1 = new Complex(1.0,2.0);
	Complex z2 = new Complex(3.0,4.0);

	System.out.println(z1);	/* toString() を定義したおかげでこれでよい*/
	System.out.println(z2);

	System.out.println(z1.getReal() + " " + z1.getImag());

	/* 
	   System.out.println(z1.realPart + " " + z1.imagPart);
	   はクラスの外では エラーになる
	*/

	System.out.println(z1.add(z2));	/* z1+z2 みたい */

	System.out.println(z1.subtract(z2)); /* z1 - z2 みたい */

	System.out.println(z1.multiply(z2)); /* z1*z2 みたい */

	/** こういうふうに代入もできる */
	Complex z3 = z1.divide(z2);  /* z3=z1/z2 みたい */
	System.out.println(z3);
	
	System.out.println(z3.equals( z1.divide(z2))); 
	/* equals は値が同じとき boolean true を返す*/

	System.out.println(z1.getConjugate());

	System.out.println(z1.getAbs());

	System.out.println(z1.getArg());

    }
}


/*
  Local Variables:
  mode: java
  compile-command: "javac -deprecation Sample10_01.java"
  End:
*/  

      
次のような結果が正しく出るとハッピーですね.
(1.0,2.0)
(3.0,4.0)
1.0 2.0
(4.0,6.0)
(-2.0,-2.0)
(-5.0,10.0)
(0.44,0.08)
true
(1.0,-2.0)
2.23606797749979
1.1071487177940904
      

課題10_02 オブジェクト指向 複素数クラス

上の Complex.java に, を追加しよう. なお, Euler の公式を使うと, ex+iy=ex(cos y + i sin y) だった. これも利用して, 複素数を System.out.println する下のようなプログラム Sample10_02 をつくろう.
/** 
    Sample10_02

    gnuplot で plot できる複素点列を印字するプログラム
    2002/06/17 Mon 21:05 hig

    gnuplot での使用方法:
  
    shell% java ComplexPlot  > datafile.1 
    gnuplot >  set ratio square # 省略可
    gnuplot >  set xlabel "Re z" # 省略可
    gnuplot >  set ylabel "Im z" # 省略可
    gnuplot >  plot [-3:3][-3:3] "datafile.1" using "(%lf,%lf)" 

*/




class Sample10_02 {

    static final int LINE_POINTS=20;
    static final int POWER_POINTS=100;

    /** メインメソッド*/
    static public void main( String[] args){

	/* ここにプログラム書いてね */

    }

}




/* emacs setting 
Local Variables:
mode: java
compile-command: "javac  -deprecation Sample10_02.java"
End:
*/

      
その結果を
s1609h017% java Sample10_02 > datafile.1
し,
s1609h017% gnuplot
gnuplot > set size square #(省略可)
gnuplot > set xlabel "Re z" #(省略可)
gnuplot > set ylabel "Im z" #(省略可)
gnuplot > plot [-3:3][-3:3] "datafile.1" using "(%lf,%lf)"
上のように gnuplot を使って複素平面で様子を見よう. 結果は, この Mathematica notebook と一致するはず.
complexsample.hbMathematica notebook
比較しながら, どの点がどの点か考えよう.
Copyright © 2002 Saburo Higuchi. All rights reserved.
Saburo HIGUCHI, hig mail address
最後の更新は次の時刻以降 2002/06/08 Sat 14:14