11/10 Java プログラミング入門(4)

今回も引き続き,プログラミング入門となる.

質問と回答

Q.
繰り返しの制御変数に double を使うのが良くないというのが良く分か らない.うまくいかない例を作って欲しい.
A.
下の例を考える.
class DoubleLoop{
  public static void main(String[] args){
    double r;
    for(r=0.0;r<1.0;r+=0.1){
      System.out.println("r="+r);
    }
  }
}
誤差なく計算できれば,ループ内を10回実行すると rは1.0になるので, そこでfor文を抜けるはずだが,実行させてみると,
r=0.0
r=0.1
r=0.2
r=0.30000000000000004
r=0.4
r=0.5
r=0.6
r=0.7
r=0.7999999999999999
r=0.8999999999999999
r=0.9999999999999999
となってしまう.誤差によって,0に0.1を10回足しても1にならない.これは, 10進法で小数点10桁以下を捨てた場合に
(1.0/3) * 3 = 0.3333333333 * 3 = 0.999999999 != 1.0
となるのと同じ原因による.2進法では1/10は切りのいい数字にはならない.
Q.
System.out.print を実行した後,System.out.flush(); を呼ばないと, バッファリングされたままで,端末に表示されないことがあると言っていたが, 抜いてもうまくいった.不要なのでは?
A.
言語処理系によって,抜いても動くことはある.センターに入っている jdk 1.1.3では大丈夫だったようだ.ただし,どこでも動くプログラムを作るた めには,System.out.flush();を入れる習慣をつけて欲しい.
Q.
実数から整数に変換するにはどうすればいいか?
A.
「(int)式」で整数に変換できる(これは演算子(operator)の一種でキャ スト演算子と呼ぶ).ただし,以下の例のように四捨五入ではないのに注意すること.
class RoundTest{
  public static void main(String[] args){
    int i,ir;
    double r= -2.0;
    for(i=0;i<=40;i++){
      ir=(int)r;
      System.out.println(r+"->"+ir);
      r+=0.1;
    }
  }
}
を実行すると
-2.0->-2
-1.9->-1
-1.7999999999999998->-1
-1.6999999999999997->-1
-1.5999999999999996->-1
-1.4999999999999996->-1
-1.3999999999999995->-1
-1.2999999999999994->-1
-1.1999999999999993->-1
-1.0999999999999992->-1
-0.9999999999999992->0
-0.8999999999999992->0
-0.7999999999999993->0
-0.6999999999999993->0
-0.5999999999999993->0
-0.49999999999999933->0
-0.39999999999999936->0
-0.2999999999999994->0
-0.19999999999999937->0
-0.09999999999999937->0
6.38378239159465E-16->0
0.10000000000000064->0
0.20000000000000065->0
0.30000000000000066->0
0.4000000000000007->0
0.5000000000000007->0
0.6000000000000006->0
0.7000000000000006->0
0.8000000000000006->0
0.9000000000000006->0
1.0000000000000007->1
1.1000000000000008->1
1.2000000000000008->1
1.300000000000001->1
1.400000000000001->1
1.500000000000001->1
1.6000000000000012->1
1.7000000000000013->1
1.8000000000000014->1
1.9000000000000015->1
2.0000000000000013->2
のようになる.四捨五入するには,0.5を足し, Math.floor()を 呼び出してからint型に変換すると良い.さきほどのプログラムを変更してみる.
class RoundTest{
  public static void main(String[] args){
    int i,ir;
    double r= -2.0;
    for(i=0;i<=40;i++){
      ir=(int)Math.floor(r+0.5);
      System.out.println(r+"->"+ir);
      r+=0.1;
    }
  }
}
実行結果は以下のようになる.
-2.0->-2
-1.9->-2
-1.7999999999999998->-2
-1.6999999999999997->-2
-1.5999999999999996->-2
-1.4999999999999996->-1
-1.3999999999999995->-1
-1.2999999999999994->-1
-1.1999999999999993->-1
-1.0999999999999992->-1
-0.9999999999999992->-1
-0.8999999999999992->-1
-0.7999999999999993->-1
-0.6999999999999993->-1
-0.5999999999999993->-1
-0.49999999999999933->0
-0.39999999999999936->0
-0.2999999999999994->0
-0.19999999999999937->0
-0.09999999999999937->0
6.38378239159465E-16->0
0.10000000000000064->0
0.20000000000000065->0
0.30000000000000066->0
0.4000000000000007->0
0.5000000000000007->1
0.6000000000000006->1
0.7000000000000006->1
0.8000000000000006->1
0.9000000000000006->1
1.0000000000000007->1
1.1000000000000008->1
1.2000000000000008->1
1.300000000000001->1
1.400000000000001->1
1.500000000000001->2
1.6000000000000012->2
1.7000000000000013->2
1.8000000000000014->2
1.9000000000000015->2
2.0000000000000013->2

前回の課題について


課題1 以下のプログラムは, 借金を年割で返済するのにかかる年数を求めるプログ ラムである.
class Test{
  public static void main(String[] argv){
    int n;
    double rate=1.01; /* 利率 */
    double a=10000.0; /* 借金の額 */
    double y=200.0; /* 1年の返済額 */
    n=0;
    while (a>0.0) {
      a = a*rate- y;
      n = n+1;
      System.out.println(n+"年後の借金の残りは"+a+"です");
    }
    System.out.println(n+"年で返済できます");
  }     
}
  1. 利率,借金の額,1年の返済額をキーボードから入力できるようにプログラムを変更しなさい
  2. 以下のうちで一番返済に時間のかかる組合せを求めなさい
    利率 1% 借金 10000 返済 200
    利率 5% 借金 10000 返済 800
    利率 10% 借金 10000 返済 1100
    利率 20% 借金 10000 返済 2100

解答例

import java.io.*;
public class Test{
  public static void main(String[] argv) throws IOException{
    int n;
    double rate; /* 利率 */
    double a; /* 借金の額 */
    double y; /* 1年の返済額 */
    BufferedReader d=new BufferedReader(new InputStreamReader(System.in));
    System.out.println("利率(%)を入力してください.");
    rate=1.0+(new Double(d.readLine()).doubleValue())*0.01;
    System.out.println("借金の額を入力してください.");
    a=new Double(d.readLine()).doubleValue();
    System.out.println("1年の返済額を入力してください.");
    y=new Double(d.readLine()).doubleValue();
    n=0;
    while (a>0.0) {
      a = a*rate- y;
      n = n+1;
      System.out.println(n+"年後の借金の残りは"+a+"です");
    }
    System.out.println(n+"年で返済できます");
  }     
}

利率 1% 借金 10000 返済 200 は
69年後の借金の残りは131.0557584615495です
70年後の借金の残りは-67.633683953835です
70年で返済できます

利率 5% 借金 10000 返済 800 は
20年後の借金の残りは80.21376913348399です
21年後の借金の残りは-715.7755424098418です
21年で返済できます

利率 10% 借金 10000 返済 1100 は
25年後の借金の残りは165.29405661167948です
26年後の借金の残りは-918.1765377271525です
26年で返済できます

利率 20% 借金 10000 返済 2100 は
16年後の借金の残りは1255.7870552481604です
17年後の借金の残りは-593.0555337022076です
17年で返済できます

返済に一番時間がかかるのは,「利率 1% 借金 10000 返済 200」の組み合わせ.

解説

入力結果を,
    String aString=d.readLine();
    a=new Double(aString).doubleValue();
のように一度 String 型の変数に取ってから,doubleに変換していいが,一カ 所でしか参照されない変数は
    a=new Double(d.readLine()).doubleValue();
のように除去することができる.

利率の入力の際,

    System.out.println("利率(%)を入力してください.");
    rate=1.0+(new Double(d.readLine()).doubleValue())*0.01;
と,%で入力を求めましたが,
    System.out.println("利率(0%の場合は1.00)を入力してください.");
    rate=new Double(d.readLine()).doubleValue();
と,比率を入力するようにしても構わない.
今回は課題が1つある.課題をこなしたら, lectures.g99.cp1-ktanaka-W-Wed-5 のニュースグループに投稿すること.
次に進む