練習問題

1. Complexの四則演算

Complex 型に四則演算を行うメソッドを追加してください.

  • Complex同士の足し算(add
    • $(a + bi) + (c + di) = (a + c) + (b + d)i$
  • Complex同士の引き算(subtract
    • $(a + bi) - (c + di) = (a - c) + (b - d)i$
  • Complex同士の掛け算(multiply
    • $(a + bi)(c + di) = (ac - bd) + (ad + bc)i$
  • Complex同士の割り算(divide
    • $(a + bi) / (c + di) = \frac{(a + bi)(c - di)}{(c + di)(c - di)} = \frac{(ac + bd) + (bc - ad)i}{c^2 + d^2}$
  • 上記4つのメソッドは1つのComplex型の値を受け取り,新たな Complex 型の実体を返します.
    • 引数で受け取った Complex型の値は変更せずに,新たな Complex型の実体を作成してください.
  • ComplexCalculatorrunメソッドに次の処理を追加してください.
    • 2つのComplex型の実体を作成してください.
      • 値はプログラム中で適当に指定してください.
    • 上記の4つのメソッドを呼び出し,四則演算の結果を出力してください.

ヒント

public class Complex{
    // ...
    Complex add(Complex value){
        // this + value の結果を返す.
    }
    Complex subtract(Complex value){
        // this - value の結果を返す.
    }
    Complex multiply(Complex value){
        // this * value の結果を返す.
    }
    Complex divide(Complex value){
        // this / value の結果を返す.
    }
}

thisvalue も値を変更せず,新たな実体を作成し,その実体の値を変更してください. 例題 conjugate が参考になるでしょう.

出力例

$ java ComplexCalculator
absoluate( 5.00 + -6.00 i) = 7.810250
conjugate( 5.00 + -6.00 i) =  5.00 +  6.00 i
 5.00 + -6.00 i +  3.00 +  2.00 i =  8.00 + -4.00 i
 5.00 + -6.00 i -  3.00 +  2.00 i =  2.00 + -8.00 i
 5.00 + -6.00 i *  3.00 +  2.00 i = 27.00 + -8.00 i
 5.00 + -6.00 i /  3.00 +  2.00 i =  0.23 + -2.15 i

2. GrandTotal改

第1回目の練習問題 4. 総和を求める再帰呼び出しを使って計算するプログラムを作成してください. クラス名は,GrandTotal2としてください. また,コマンドライン引数で最大値を与えられるようにしてください.

出力例

$ java GrandTotal2
1から10までの総和は55です.
$ java GrandTotal2 10
1から10までの総和は55です.
$ java GrandTotal2 100
1から100までの総和は5050です.
$ java GrandTotal2 90
1から90までの総和は4095です.

3. Fibonacci数列 改

第2回目の練習問題 5. Fibonacci数列再帰呼び出しを使って計算してみましょう. Fibonacci数列の$n$項目の値を出力してください. クラス名はFibonacci2としてください.

コマンドライン引数に値が指定されない場合は,10項目が指定されたものとしてください. コマンドライン引数に複数個の数値が与えられた場合,全ての数値に対して結果を出力してください.

出力例

$ java Fibonacci2
55
$ java Fibonacci2 1 2
fibonacci(1) = 1
fibonacci(2) = 1
$ java Fibonacci2 4 10 20
fibonacci(4) = 3
fibonacci(10) = 55
fibonacci(20) = 6765
$ java Fibonacci2 40
fibonacci(40) = 102334155

4. Fibonacci数列 改2

第2回目の練習問題 5. Fibonacci数列を改良し,桁あふれを起こさないようにしてください. 再帰呼び出しではなく,単純な繰り返しでFibonacci数列の$n$項目を求めてください(単純な再帰呼び出しにすると,非常に遅くなるため). クラス名はBigFibonacciとしてください. Fibonacci数列を Integer型で扱うと,第47項目の計算で桁あふれを起こします.

コマンドライン引数に値が指定されない場合は,10項目が指定されたものとしてください. コマンドライン引数に複数個の数値が与えられた場合,全ての数値に対して結果を出力してください.

出力例

$ java BigFibonacci
fibonacci(10) = 55
$ java BigFibonacci 10 30 46 47 48 49 50
fibonacci(10) = 55
fibonacci(30) = 832040
fibonacci(46) = 1836311903
fibonacci(47) = 2971215073
fibonacci(48) = 4807526976
fibonacci(49) = 7778742049
fibonacci(50) = 12586269025

5. 線形合同法による擬似乱数列

線形合同法(Linear Congruential Generators)を用いて,0〜1の範囲の乱数をコマンドライン引数で指定された数だけ求めてください. コマンドライン引数で何も指定されなかった場合は,10が指定されたものとしてください. クラス名は LinearCongruentialGenerator としてください.

このプログラムも,素数の一覧 と同じように ArrayList<Double>を返すメソッドを作成し, 返されたArrayList<Double>の実体をそのままSystem.out.printlnに渡してください.

線形合同法は,擬似乱数を発生させるアルゴリズムです.以下の漸化式で求めます.

$X_{n+1}=(A\times X_n + B) \mod M$

$A$,$B$,$M$は定数です.$A$は自分の誕生日(月日.3桁もしくは4桁),$B$は1, $M$は65535,$X_0$は自分の年齢としてください. 完成すれば,$A$,$B$,$M$,$X_0$の値を変更して結果がどのように変わるかを確認しましょう. ただし,$A<M$,$B<M$である必要があります.

この問題は,必ずしも再帰呼び出しで作成する必要はありません.

なお,C言語の rand 関数は,この線形合同法を用いて計算されています.

この練習問題で作成した乱数の安全性について

出力例

各自の出力結果は,以下のものと異なる値になります.

$ java LinearCongruentialGenerator
[0.019073486328125, 0.308502197265625, 0.329376220703125, 0.855133056640625, 0.471710205078125, 0.077545166015625, 0.383575439453125, 0.413238525390625, 0.002471923828125, 0.299713134765625]
$ java LinearCongruentialGenerator 2
[0.019073486328125, 0.308502197265625]
$ java LinearCongruentialGenerator 5
[0.019073486328125, 0.308502197265625, 0.329376220703125, 0.855133056640625, 0.471710205078125]

ヒント

乱数値はDouble型で求めますが,$X_{n+1}$ の計算式はInteger型で計算する必要があります. つまり,結果を保存するとき,$X_{n+1}$ を $M$で割り,Integer型からDouble型に変換する必要があります.

ArrayList<Double> random(Integer max){
  ArrayList<Double> results = // 結果を格納するリストを作成する.
  Integer a, xn, b, m;
  xn = 20; // X0(自分の年齢)
  // a, b, m にも初期値を代入する.
  // 以下の2行を指定回数繰り返す.
      xn = // 線形合同法の計算式に従い,X_n+1 を求める.
      results.add(1.0 * xn / m); 
      // xnを0.0〜1.0の範囲に変換してリストに追加する.
  return results;
}

6. 回文チェッカー

コマンドライン引数で与えられた文字列(複数指定可)が回文(palindrome)であるかどうかを確認するプログラムを作成してください. 回文とは,始めから読んだ場合と終わりから読んだ場合とで,文字の出現する順番が同じである文字列のことを指します (本来は意味の通じるように,という条件もありますが,プログラムでは判断するのは難しいので,意味については関知しないものとします).

クラス名は PalindromeChecker としてください.

出力例

$ java PalindromeChecker akasaka
akasaka: true
$ java PalindromeChecker ABBA madamimadam
ABBA: true
madamimadam: true # Madam, I'm Adam
$ java PalindromeChecker あかさか わにのにわ つつみがみっつ
あかさか: false
わにのにわ: true
つつみがみっつ: false

一般的な回文では,濁音,半濁音,促音,拗音は清音と同一視されます (つつみがみっつは回文として扱われる). しかし,処理がややこしくなりますので,上記の条件は無視して良いです (つつみがみっつは回文として扱わなくて良いです).

ヒント1: 文字列のn文字目を取得する.

文字列(String型)のn文字目を取得するには,charAtメソッドを用います. charAt メソッドは1つのInteger型の値を受け取り,Character型の変数を返します.

String string = "abracadabra";
Character c1 = string.charAt(0);
    // => 'a'(1文字目の'a')
Character c1 = string.charAt(string.length() - 1);
    // => 'a'(最後の文字の'a')

ヒント2: 部分文字列を取得する

文字列(String型)の部分文字列を取得するには,substringメソッドを用います. substring メソッドは1つ,もしくは2つのInteger型を受け取ります.

String string = "abracadabra";
String sub1 = string.substring(2);
    // => "racadabra"
String sub2 = string.substring(2, string.length() - 2);
    // => "racadab"
String sub3 = string.substring(1, string.length() - 1);
    // => "bracadabr"

ヒント3: 考え方

次の考え方で回文であるかを判定できます.

まず,isPalindrome メソッドを定義しましょう. 引数は1つのString型を受け取り,Boolean型を返します.

  1. メソッドの最初で,文字列の長さが1文字以下ならば回文であると判定します.
  2. そうでないなら,受け取った文字列から最初の文字(first)と最後の文字(last)を取得します(文字列のn文字目を取得する).
  3. firstlast が一致しなければ,回文ではないと判定します.
  4. 最初と最後の文字を除いた部分文字列を取得します(部分文字列を取得する).
  5. 取得した部分文字列を引数にして,isPalindromeを呼び出し,その結果をメソッドの返り値とします.

以下も参照してください.

7. ニュートン法による立方根の計算

ニュートン法による平方根の計算を参考に立方根を求めてください. クラス名は,CubicRootとします.

出力例

$ java CubicRoot 2 3 4 5 6 8 27
cubic_root(2.000000) = 1.259921
cubic_root(3.000000) = 1.442250
cubic_root(4.000000) = 1.587401
cubic_root(5.000000) = 1.709976
cubic_root(6.000000) = 1.817121
cubic_root(8.000000) = 2.000000
cubic_root(27.000000) = 3.000000