第10週目課題

課題1001

コンソールから正の整数 n を入力させ、1からnまでの逆数の和を計算して表示するプログラム HarmonicSeries.java をパッケージ j1.lesson10 に作成しなさい。

以下の擬似コードが表すメソッド harmonic を作成すること。このharmonicは一つの引数 (int n) を持つ。引数で与えられた n を元に1/1+1/2+1/3+...+1/nを計算して、結果をdouble型で返すこと。

sum = 0
kの値を1からnまで1ずつ増やしながら以下の計算を繰り返す
    sum に 1/k を加える
sum を返す

このプログラムではまずmainメソッド内でコンソールの入力から1つの整数を取得し、それを用いて harmonic メソッド内で逆数の和の計算を行い、最後にmainメソッド内で結果を表示する。

mainメソッドの動作を表す擬似コードは以下の通りである。出力する文字列などは以下の擬似コードに従うこと。

print "正の整数を入力:"
n = コンソール入力 (整数)
nが0以下だったら
    print "正の整数を入力してください。"
そうでなかったら
    print "nまでの調和級数の部分和はharmonic(n)"

ただし、最後の行にある"nまでの調和級数の部分和はharmonic(n)" のうち、n はコンソールから入力された値、harmonic(n) は harmonicメソッドの戻り値とする。

結果の例

入力に10 を指定した場合、プログラムを終了まで実行した際のコンソールは以下のようになっている。

正の整数を入力: 10
10までの調和級数の部分和は2.9289682539682538

手順

指定した箇所で必ずテストを行うこと。

  1. powerメソッドに対する詳細な擬似コードを作成する
  2. パッケージ j1.lesson10 にクラス HarmonicSeries を作成 (ファイル名は HarmonicSeries.javaとなる)
  3. クラス内に throws IOException の指定をした mainメソッド (public static void main(String[] args) throws IOException { }) を作成
  4. クラス内に必要なメソッド (harmonic) の骨格を作成 (こちらには throws IOException は必要ない)
  5. テスト項目「HarmonicSeries に対する骨格テスト」をパス
  6. 擬似コードを各メソッドにコメントとして貼り付ける
  7. 擬似コードに対するプログラムを書く
  8. 実際に実行して動作を確認する

テストの失敗メッセージ

骨格テスト

メッセージ 詳細
(クラス名), existence パッケージ内に課題で指定したクラスが存在していない。パッケージやクラス名を確認
(メソッド名), existence 指定されたメソッドが存在しない
(メソッド名), public メソッドを作る際に public が抜けている
(メソッド名), static メソッドを作る際に static が抜けている
(メソッド名), type void メソッドを作る際に void 以外を指定している
(メソッド名), throws ... メソッドを作る際に throws... の指定がない

課題1002

コンソールから1より大きい実数xを入力させ、1/1+1/2+...+1/n > x となる最小の整数nの値を計算して表示するプログラム HarmonicUntil.java をパッケージ j1.lesson10 に作成しなさい。

以下の擬似コードが表すメソッド harmonicUntil を作成すること。このharmonicUntilは一つの引数 (double x) を持つ。引数で与えられた x を元に 1/1+1/2+...+1/n > x となる最小の整数nを計算して、結果をint型で返すこと。

sum = 0
n = 0
sum < x の間以下の計算を繰り返す
    nに1を加える
    sum に 1/n を加える
n を返す

このプログラムではまずmainメソッド内でコンソールの入力から1つの実数を取得し、それを用いて harmonicUntil メソッド内で調和級数の部分和がxを超えるための最小の項数の計算を行い、最後にmainメソッド内で結果を表示する。

mainメソッドの動作を表す擬似コードは以下の通りである。出力する文字列などは以下の擬似コードに従うこと。

print "1より大きい実数を入力:"
x = コンソール入力 (実数)
xが1以下だったら
    print "1より大きい実数を入力してください。"
そうでなかったら
    print "nの値はharmonicUntil(x)"

ただし、最後の行にある"nの値はharmonicUntil(x)" のうち、x はコンソールから入力された値、harmonicUntil(x) は harmonicUntilメソッドの戻り値とする。

結果の例

入力に10 を指定した場合、プログラムを終了まで実行した際のコンソールは以下のようになっている。

1より大きい実数を入力: 10
nの値は12367

確認してみよう。課題1001のプログラムHarmonicSeriesの入力に12367を指定した場合、プログラムを終了まで実行した際のコンソールは以下のようになっている。

正の整数を入力: 12367
12367までの調和級数の部分和は10.000043008275778

同じくHarmonicSeriesの入力に12366を指定した場合、プログラムを終了まで実行した際のコンソールは以下のようになっている。

正の整数を入力: 12366
12366までの調和級数の部分和は9.99996214792161

手順

指定した箇所で必ずテストを行うこと。

  1. harmonicUntilメソッドに対する詳細な擬似コードを作成する
  2. パッケージ j1.lesson10 にクラス HarmonicUntil を作成 (ファイル名は HarmonicUntil.javaとなる)
  3. クラス内に throws IOException の指定をした mainメソッド (public static void main(String[] args) throws IOException { }) を作成
  4. クラス内に必要なメソッド (harmonic) の骨格を作成 (こちらには throws IOException は必要ない)
  5. テスト項目「HarmonicUntil に対する骨格テスト」をパス
  6. 擬似コードを各メソッドにコメントとして貼り付ける
  7. 擬似コードに対するプログラムを書く
  8. 実際に実行して動作を確認する

課題1003 (optional)

コンソールから実数 m と整数 n を入力させ、mnを計算して表示するプログラム BinaryPowerOpt.java をパッケージ j1.lesson10 に作成しなさい。このnは2のべき乗つまり2*2*...*2と素因数分解できる整数に限るものとする。この課題は次の課題1004への準備体操の意味がある。

ただし、以下の概略レベルの擬似コードを元に、プログラムを作成すること。

mのn乗
    if n=1
        結果は: m
    そうでなければ
        sub = mのn/2乗
        結果は: sub*sub

上記の擬似コードが表すメソッドの名前は binaryPower とし、二つの引数 (double m, int n) を持つ。引数で与えられた m, n を元に mn を計算し、結果をdouble型の値として返すこと。

このbinaryPowerの考え方は単純である。例えば3.0の16乗を計算したければ、3.0の8乗を計算してそれを平方すればよい。3.0の8乗は3.0の4乗を計算してそれを平方すればよい。これを0乗まで再帰すれば掛け算は4回で済む。真正直にやれば15回である。

入力された整数nが2のべき乗であるか判定したい。そこで以下の擬似コードがあらわすメソッドisPowerOf2を用意する。このメソッドは正の整数(int n)を引数に持つ。nが2のべき乗であればtrueを返し、そうでなければfalseを返す。

nが2で割り切れる間以下を繰り返す
    nにnを2で割った値を代入する
nが1なら
    trueを返す
そうでなければ
    falseを返す

このプログラムではまずmainメソッド内でコンソールの入力から1つの実数と1つの整数を順に取得し、それらを用いて binaryPower メソッド内でべき乗の計算を行い、最後にmainメソッド内で結果を表示する。本プログラムでは、Math.pow(double,double) の使用を禁止する。

mainメソッドの動作を表す擬似コードは以下の通りである。出力する文字列などは以下の擬似コードに従うこと。

print "mの値を入力:"
m = コンソール入力 (実数)
print "nの値を入力:"
n = コンソール入力 (整数)
もしnが正で2のべき乗なら
    print "mのn乗はbinaryPower(m,n)"
そうでないなら
    print "nには2のべき乗となる正の整数を入力してください。"

ただし、printの引数にある "mのn乗はbinaryPower(m,n)" のうち、m はコンソールから1番目に入力された値、n はコンソールから2番目に入力された値、binaryPower(m,n) は mn を計算して求めた結果とする。

結果の例

入力に順に 2.0, 8 を指定した場合、プログラムを終了まで実行した際のコンソールは以下のようになっている。

mの値を入力: 2.0
nの値を入力: 8
2.0の8乗は256.0

手順

指定した箇所で必ずテストを行うこと。

  1. powerメソッドに対する詳細な擬似コードを作成する
  2. パッケージ j1.lesson10 にクラス BinaryPowerOpt を作成 (ファイル名は BinaryPowerOpt.javaとなる)
  3. クラス内に throws IOException の指定をした mainメソッド (public static void main(String[] args) throws IOException { }) を作成
  4. クラス内に必要なメソッド (power) の骨格を作成 (こちらには throws IOException は必要ない)
  5. テスト項目「BinaryPowerOpt に対する骨格テスト」をパス
  6. 擬似コードを各メソッドにコメントとして貼り付ける
  7. 擬似コードに対するプログラムを書く
  8. 実際に実行して動作を確認する

テストの失敗メッセージ

骨格テスト

メッセージ 詳細
(クラス名), existence パッケージ内に課題で指定したクラスが存在していない。パッケージやクラス名を確認
(メソッド名), existence 指定されたメソッドが存在しない
(メソッド名), public メソッドを作る際に public が抜けている
(メソッド名), static メソッドを作る際に static が抜けている
(メソッド名), type void メソッドを作る際に void 以外を指定している
(メソッド名), throws ... メソッドを作る際に throws... の指定がない

課題1004 (optional)

コンソールから実数 m と整数 n を入力させ、mnを計算して表示するプログラム PowerOpt.java をパッケージ j1.lesson10 に作成しなさい。

ただし、以下の概略レベルの擬似コードを元に、プログラムを作成すること。


上記の擬似コードが表すメソッドの名前は power とし、二つの引数 (double m, int n) を持つ。引数で与えられた m, n を元に mn を計算し、結果をdouble型の値として返すこと。また、このメソッドでは 1.0000000012000000000 を演習環境で 5 秒以内に計算できること。

このプログラムではまずmainメソッド内でコンソールの入力から1つの実数と1つの整数を順に取得し、それらを用いて power メソッド内でべき乗の計算を行い、最後にmainメソッド内で結果を表示する。本プログラムでは、Math.pow(double,double) の使用を禁止する。

mainメソッドの動作を表す擬似コードは以下の通りである。出力する文字列などは以下の擬似コードに従うこと。

print "mの値を入力:"
m = コンソール入力 (実数)
print "nの値を入力:"
n = コンソール入力 (整数)
print "mのn乗はpower(m,n)"

ただし、最後の行にある "mのn乗はpower(m,n)" のうち、m はコンソールから1番目に入力された値、n はコンソールから2番目に入力された値、power(m,n) は mn を計算して求めた結果とする。

結果の例

入力に順に 1.3, -2 を指定した場合、プログラムを終了まで実行した際のコンソールは以下のようになっている。

mの値を入力:1.3
nの値を入力:-2
1.3の-2乗は0.5917159763313609

手順

指定した箇所で必ずテストを行うこと。

  1. powerメソッドに対する詳細な擬似コードを作成する
  2. パッケージ j1.lesson10 にクラス PowerOpt を作成 (ファイル名は PowerOpt.javaとなる)
  3. クラス内に throws IOException の指定をした mainメソッド (public static void main(String[] args) throws IOException { }) を作成
  4. クラス内に必要なメソッド (power) の骨格を作成 (こちらには throws IOException は必要ない)
  5. テスト項目「PowerOpt に対する骨格テスト」をパス
  6. 擬似コードを各メソッドにコメントとして貼り付ける
  7. 擬似コードに対するプログラムを書く
  8. 実際に実行して動作を確認する

ヒント

この課題では、mnを計算する際にmn/2を計算し、それを2回掛け合わせることによってmnを計算している。

ただし、nが奇数のときは mn = m * m(n-1)/2 * m(n-1)/2 を計算している。これによって、nが2のべき乗でなくても問題なく動作する。

テストの失敗メッセージ

骨格テスト

メッセージ 詳細
(クラス名), existence パッケージ内に課題で指定したクラスが存在していない。パッケージやクラス名を確認
(メソッド名), existence 指定されたメソッドが存在しない
(メソッド名), public メソッドを作る際に public が抜けている
(メソッド名), static メソッドを作る際に static が抜けている
(メソッド名), type void メソッドを作る際に void 以外を指定している
(メソッド名), throws ... メソッドを作る際に throws... の指定がない

課題1005 (optional)

課題1001で作成したプログラムに対する単体テストプログラム PowerOptTest.java をパッケージ j1.lesson10 に作成しなさい。

このテストプログラムは、演習で行った際と同様にJUnitを用いて作成すること。また、テストを行うためのメソッドとして、testPower() メソッドを作成すること。

テストケースは以下の通りとする (期待値は各自で計算すること)。

テスト対象 引数 許容誤差
power(double,int) (-2.0, -5) 0.0001
power(double,int) (-2.0, -1) 0.0001
power(double,int) (-2.0, 0) 0.0001
power(double,int) (-2.0, 1) 0.0001
power(double,int) (-2.0, 2) 0.0001
power(double,int) (-2.0, 3) 0.0001
power(double,int) (2.0, -5) 0.0001
power(double,int) (2.0, -1) 0.0001
power(double,int) (2.0, 0) 0.0001
power(double,int) (2.0, 1) 0.0001
power(double,int) (2.0, 2) 0.0001
power(double,int) (2.0, 3) 0.0001
power(double,int) (0.0, 1) 0.0001

double 型の値をテストする場合、assertEqualsに許容誤差を書かなくてはならない。例えばPowerOpt.power(3.0, 2)をassertEqualsで表現したとすると

assertEquals(9.0, PowerOpt.power(3.0, 2), 0.0001);

のように書けばよい。

手順

指定した箇所で必ずテストを行うこと。

  1. パッケージ j1.lesson10 にクラス PowerOptTest を JUnit・テストケース として作成
  2. testPower() メソッドにテストケースを記述
  3. 作成したテストケースを実行して動作を確認
  4. 「PowerOpt に対するテスト一式」 をパス

テストの失敗メッセージ

こちら側で用意したテストの失敗時のメッセージを掲載する。

骨格テスト

メッセージ 詳細
(クラス名), existence パッケージ内に課題で指定したクラスが存在していない。パッケージやクラス名を確認
(メソッド名), existence 指定されたメソッドが存在しない
(メソッド名), public メソッドを作る際に public が抜けている
(メソッド名), static メソッドを作る際に static が抜けている
(メソッド名), type <T> メソッドを作る際に戻り値の型が違う。正しくは <T>
(メソッド名), throws ... メソッドを作る際に throws... の指定がない

単体テストの項目

テスト失敗時に「Results」の欄の左側に出る「test~」は、テストの項目名を表している。

項目名 詳細
Power_huge power(1.000000001, 2000000000) を実行

他にもあるが割愛する。

機能テスト

メッセージ 詳細
余計な入力を待っていると考えられます コンソール入力を取得する命令を必要以上に行っていないか確認
次の入力を変換できませんでした (???) ??? を取得しようとして失敗している。コンソール入力を取得する命令を確認
期待された結果と異なります 出力された結果が期待された値と異なる。「期待された値」と「実際の値」を比較 (エラーメッセージが出力されているエリアの下のほうにあるバーをスクロールさせれば見ることができる) し確認。他にも直接プログラムを実行して結果を調べたり、エラーメッセージの2行目にあるat以下を参考にプログラムを見直す
無限ループの可能性 一定時間内にプログラムが終了しなかった。ループが無限に続いていないか確認

メタテスト

メッセージ 詳細
(クラス名) テストが失敗している
testcase (メソッド名).(引数) 指定されたメソッドを指定された引数でテストしていない

課題1005 (optional)

コンソールから 0 以外の実数値 c を入力させ、c の立方根をニュートン法によって計算して結果を表示するプログラム Newton.java をパッケージ j1.lesson10 に作成しなさい。

ニュートン法で c の立方根を求める場合、以下のようなアルゴリズムになる。

  1. f(x) - c = 0 とおく
  2. x0 = c とおく
  3. y = f(x) - c の x = x0 における接線を引き、x軸と交わったところを x1 とし、以下同様な手順で x2, x3, .. ,xn と求めていく
  4. | xn - xn-1 | / | xn | < 0.0001 となったときの xn が f(x) = c となる x の 近似値
  5. 手順 3 へ戻る

ただし、xn を求めるには、以下の計算式を使う。


本課題は、以下の概略レベルの擬似コードを元に、プログラムを作成すること。


上記の擬似コードが表すメソッドの名前は newton とし、一つの引数 (double c) を持つ。この引数で与えられた c と後ほど用意する f(x), g(x) を用いてニュートン法を適用し、c の立方根を計算し、結果を double 型の値として返すこと。

上記の擬似コードに出てくる f(x), g(x) は以下のような関数である。


これらをそれぞれJavaのメソッド f(double x), g(double x) として Newton クラス内に作成し、newtonメソッドから呼び出せるようにすること。それぞれの戻り値型は double 型とする。

このプログラムではまずmainメソッド内でコンソールの入力から1つの実数を取得し、それを用いて newton メソッド内で入力された値の立方根を計算し、最後にmainメソッド内で結果を表示する。

mainメソッドの動作を表す擬似コードは以下の通りである。出力する文字列などは以下の擬似コードに従うこと。

print "実数を入力:"
c = コンソール入力 (実数)
print "cの立方根はnewton(c)"

ただし、最後の行にある "cの立方根はnewton(c)" のうち、c はコンソールから入力された値、newton(c) は newtonメソッドを実引数としてコンソールから入力された値を与えて呼び出した結果とする。

結果の例

入力に64.0を指定した場合、プログラムを終了まで実行した際のコンソールは以下のようになっている 。

実数を入力:64
64.0の立方根は4.000000000000065

手順

指定した箇所で必ずテストを行うこと。

  1. newtonメソッドに対する詳細な擬似コードを作成する
  2. パッケージ j1.lesson10 にクラス Newton を作成 (ファイル名は Newton.javaとなる)
  3. クラス内に throws IOException の指定をした mainメソッド (public static void main(String[] args) throws IOException { }) を作成
  4. クラス内に必要なメソッドの骨格を作成 (こちらには throws IOException は必要ない)
  5. テスト項目「Newton に対する骨格テスト」をパス
  6. 擬似コードを各メソッドにコメントとして貼り付ける
  7. 擬似コードに対するプログラムを書く
  8. 実際に実行して動作を確認する

テストの失敗メッセージ

骨格テスト

メッセージ 詳細
(クラス名), existence パッケージ内に課題で指定したクラスが存在していない。パッケージやクラス名を確認
(メソッド名), existence 指定されたメソッドが存在しない
(メソッド名), public メソッドを作る際に public が抜けている
(メソッド名), static メソッドを作る際に static が抜けている
(メソッド名), type void メソッドを作る際に void 以外を指定している
(メソッド名), throws ... メソッドを作る際に throws... の指定がない

課題1006 (optional)

課題1003で作成したプログラムに対する単体テストプログラム NewtonTest.java をパッケージ j1.lesson10 に作成しなさい。

このテストプログラムは、演習で行った際と同様にJUnitを用いて作成すること。また、テストを行うためのメソッドとして、testNewton(), testF(), testG() メソッドを作成すること。

テストケースは以下の通りとする (期待値は各自で計算すること)。

テスト対象 引数 許容誤差
f(double) (-2.0) 0.0001
f(double) (0.0) 0.0001
f(double) (2.0) 0.0001
g(double) (-2.0) 0.0001
g(double) (0.0) 0.0001
g(double) (2.0) 0.0001
newton(double) (-27.0) 0.0001
newton(double) (-1.0) 0.0001
newton(double) (-0.001) 0.0001
newton(double) (0.001) 0.0001
newton(double) (1.0) 0.0001
newton(double) (27.0) 0.0001

f(double)に対するテストはtestF()へ、g(double)に対するテストはtestG()へ、newton(double)に対するテストはtestNewton()内に記述すること。

手順

指定した箇所で必ずテストを行うこと。

  1. パッケージ j1.lesson10 にクラス NewtonTest を JUnit・テストケース として作成
  2. testF(), testG(), testNewton() メソッドにそれぞれテストケースを記述
  3. 作成したテストケースを実行して動作を確認
  4. 「Newton に対するテスト一式」 をパス

テストの失敗メッセージ

骨格テスト

メッセージ 詳細
(クラス名), existence パッケージ内に課題で指定したクラスが存在していない。パッケージやクラス名を確認
(メソッド名), existence 指定されたメソッドが存在しない
(メソッド名), public メソッドを作る際に public が抜けている
(メソッド名), static メソッドを作る際に static が抜けている
(メソッド名), type <T> メソッドを作る際に戻り値の型が違う。正しくは <T>
(メソッド名), throws ... メソッドを作る際に throws... の指定がない

単体テスト

メッセージ 詳細
(メソッド名), 期待された結果と異なります (メソッド名)を起動した結果が期待された結果と異なる。テスト項目を参照

機能テスト

メッセージ 詳細
余計な入力を待っていると考えられます コンソール入力を取得する命令を必要以上に行っていないか確認
次の入力を変換できませんでした (???) ??? を取得しようとして失敗している。コンソール入力を取得する命令を確認
期待された結果と異なります 出力された結果が期待された値と異なる。「期待された値」と「実際の値」を比較 (エラーメッセージが出力されているエリアの下のほうにあるバーをスクロールさせれば見ることができる) し確認。他にも直接プログラムを実行して結果を調べたり、エラーメッセージの2行目にあるat以下を参考にプログラムを見直す
無限ループの可能性 一定時間内にプログラムが終了しなかった。ループが無限に続いていないか確認

メタテスト

メッセージ 詳細
(クラス名) テストが失敗している
testcase (メソッド名).(引数) 指定されたメソッドを指定された引数でテストしていない

課題1008 (special)

以下のような虫食い算 (Xには0~9の任意の値が入り、a,bにはユーザから入力された0~9の値が入る) を解くプログラム Alphametic3.java を package j1.lesson10 に作成しなさい。

    X X
*   X X
--------
  X X X
X a X
--------
X b X X

各桁の最上位桁には 0 は入らない。

指針もテストも与えない。好きなようにプログラムを作成すること。

ヒント

擬似コードを示す。

プログラム全体
    "aの値を入力:" と表示
    a = コンソールへの入力
    if a が負の値 または a が 10 以上
        "不正な入力です" と表示
        終了
    "bの値を入力:" と表示
    b = コンソールへの入力
    if b が負の値 または b が 10 以上
        "不正な入力です" と表示
        終了
    a, b の値を使って、虫食い算の全ての可能性を算出して表示する
与えられた虫食い算を解く(a, b)
    for 被乗数 を 10 から 99 まで
        for 乗数 を 10 から 99 まで
            1段目 = 被乗数 * (乗数の1桁目)
            2段目 = 被乗数 * (乗数の2桁目)
            結果 = 1段目 + 2段目 * 10
            if 1段目が 3桁 かつ
               2段目が 3桁 かつ
               結果が 4桁 かつ
               2段目の2桁目が a と等しい かつ
               結果の3桁目が b と等しい ならば
                "(被乗数, 乗数)" を表示して改行
桁数を計算する(value)
    桁数の初期値を0に設定
    while value が 0 でない
        value の値を10で割って、小数点以下を切り捨て
        桁数を 1 増やす
    ここまでの桁数を返す
指定した桁の値を取得する (value, n)
    10 の n-1 乗を作成する
    value の値を10のn-1乗で割って、小数点以下を切り捨て
    さらにその値を10で割った余りを返す