解答例(10月24日分)



練習3-1
文字列として与えられた2進数から10進数を
計算するプログラムを作れ。

解答例(佐々木俊也さん)
class BiToDeci { //2進数から10進数への変換
  public static void main(String[] arg){
    String binaryNumber="1101"; //文字列として与えられた2進数
    int NumberOfDigits = binaryNumber.length(); //ビット数
    int index; //現在注目している桁数をしまう変数
    int DecimalNumber=0; //10進数の値
    int bit; //index桁目のビットをしまう変数
    int base=1; //index桁目の基数
    for (index = NumberOfDigits-1; index >= 0; index = index - 1){
      /* 最上位がindex=0なので最下位はindex=NumberOfDigits-1 */
      bit = binaryNumber.charAt(index) - '0'; //index桁目のビット
      DecimalNumber=DecimalNumber+base*bit; //10進数に変換
      base = base * 2; //基数を次の桁に
    }
    System.out.println("2進数"+binaryNumber+"を10進数にすると"+
                       DecimalNumber+"です。");
  }
}

実行結果
2進数1101を10進数にすると13です。

コメント
計算を簡単にするために桁をプリントのやり方と逆にしています。

解答例(河野佐代子さん)
class Shinhou6 { // 2進数と10進数
  public static void main(String[] args) {
    String binaryNumber = "1101"; // 文字列で表した2進法
    int numberOfDigits = binaryNumber.length(); //ビット数
    int index; //現在注目している桁数をしまう変数
    int decimalNumber = 0;//10進数の値
    int base = 8; //基数
    for (index = 3; -1 < index ; index = index - 1) {
      int bit =binaryNumber.charAt(3-index) - '0';//index桁目のビット
      System.out.println("第"+index+"桁目は"+bit+"です");
      decimalNumber = decimalNumber + base*bit; //10進数に変換する。
      base = base/2 ;
    }
      System.out.println("10進数では"+decimalNumber+"です");
  }
}

上位の桁から表示されるのは、なんとなく気持が悪いので、
先生からのアドバイスも借りつつ、上のようなプログラムをつくりました。

実行結果は

第3桁目は1です
第2桁目は1です
第1桁目は0です
第0桁目は1です
10進数では13です

となりました。


練習3-2
for文を使って一定回数の繰り返しを行う場合、
条件を大小関係で書くのが普通である。これを例えば
下のように、「等しくない」ことを条件にして実行するとどうなるか?
またその理由は?

double year; // 現在の年数
for (year = 1; year != 10; year = year + 0.1) // 10分の1年刻みごとの繰返し
  System.out.println("現在の年数は"+year+"です。");
解答例(佐々木俊也さん)
class year { //数値誤差
  public static void main(String[] args){
    double year; //現在の年数
    for (year=1; year!=10; year=year+0.1) //10分の1年ごとの繰り返し
      System.out.println("現在の年数は"+year+"です。");
  }
}

コメント
この場合、yearが10になった時点でfor文から抜けると思われるが、
実際には永遠に繰り返す。
(止めるときはControlキーとCを押す)
これは、表示結果を見れば分かるが、
わずかな誤差のためにyearが10になることはない。
10の前後では、現在の年数は9.999999999999982です。
現在の年数は10.099999999999982です。
と表示される。


練習3-3
金利が 0.1%, 0.2%, ..., 1.0% の場合について、
それぞれ10万円を10年間預けたときの残高を計算して表示させよ。
(ヒント: for文の中にfor文を書く。)
解答例(蒋 弥能(ショウ ミノウ)さん)
class interest   //10年後の残高を計算する
{
 public static void main(String[] args){
 double interest;  //利率
 int currentyear;         //何年後かを数える変数
 double base=100000;         // currentyear年目の残高
   for(interest=0.001;interest<=0.01;interest=interest+0.001){
   //利率1.001から1.01までを順に実行
    double balance=base;
   for(currentyear=1;currentyear<=10;currentyear=currentyear+1){
   //1年後から10年後までを順に実行
    balance=balance*(1+interest);    //残高を増やす
    }
    System.out.println("金利は"+interest+"のとき十年後残高は"+balance+"です");
     //10年後の残高
   }
 }
}
実行結果は
金利は0.0010のとき十年後残高は101004.51202102509です
金利は0.0020のとき十年後残高は102018.09633680772です
金利は0.0030のとき十年後残高は103040.82570713882です
金利は0.0040のとき十年後残高は104072.773401891です
金利は0.0050のとき十年後残高は105114.01320407893です
金利は0.0060のとき十年後残高は106164.61941293835です
金利は0.0070のとき十年後残高は107224.66684701681です
金利は0.0080のとき十年後残高は108294.23084728388です
金利は0.009000000000000001のとき十年後残高は109373.38728025254です



練習3-4
for文は、while文に「繰り返しの最初に行う計算」と
「繰り返しを続ける際に行う計算」が書けるようにしたものと見なせる。
いま、

for (A; B; C) { D; E; ... Z; }

というfor文があったとき、
これと同じ計算をするwhile文はどうなるかを示せ。
また、図1をwhile文を使って書き直せ。

解答例(佐々木俊也さん)
for(A;B;C){D;E:…Z;}
は、以下のように書き直せる。
A;
while(B){
D;
E;
:
Z;
C;
}
したがって、図1は以下のように書き直せる。
class Saving_while{
  public static void main(String[] arg){
    double interest = 1.0045; //利率
    int years =10; //計算する期間
    int currentYear; //何年後かを数える変数
    double balance =100000; //currentYear年目の残高
    currentYear=1;
    while(currentYear<=years){
      balance=balance*interest;
      currentYear=currentYear+1;
    }
    System.out.println(balance);  //years年後の残高
  }
}

for文を使った方がすっきりと書ける。



練習3-5
テキストのdo-while文の説明を読み、
上の練習にならってwhile文への書き換えを考えよ。
TAによる解答例
A;
while(B){

は、基本的には以下のように書き直せる。
A;
do {
D;E;...;Z;
C;
} while(B);

ただし、while文と異なり、
do文では{}の中(D;E;...;Z;)が無条件に一度実行される
ので注意が必要。


練習3-6
10年後に元金が2倍になる最低の金利を求めたい。
金利を 0.1%, 0.2%, ... と 0.1% 刻みで変化させ、
10年後の残高が 2 倍未満の間繰り返すことで求めよ。
(ヒント: do〜while 文を使った方がすっきりと書ける
かも知れない。)
解答例(佐々木俊也さん)
class nest2{ //二重の繰り返し(2)
  public static void main(String[] arg){
    double interest; //金利
    double principal = 100000; //元金
    double balance=principal; //残高
    double targetrate=2; //目標とする倍率
    double targetbalance=principal*targetrate; //目標とする金額
    int term=10; //預ける期間
    int year; //現在の年数
    interest=0; //金利の初期設定
    while(balance<targetbalance){
      // 残高が目標金額を下回っている間以下を繰り返す
      interest=interest+0.1;
      balance=principal;
      for(year=1;year<=term;year=year+1){
        balance=balance+balance*(interest/100); //year年後の残高の計算
      }
      System.out.println("元金"+principal+"円で金利"+interest+"%の時の"+
                         term+"年後の残高は");
      System.out.println(balance+"円です。");
      //長くなったので2行に表示を分けました。
    }
    System.out.println("よって、"+term+"年後の残高が"+targetrate+
                       "倍になる最低の金利は"+interest+"%です。");
  }
}

実行結果
(略)
元金100000.0円で金利7.099999999999991%の時の10年後の残高は
198561.3460801142円です。
元金100000.0円で金利7.19999999999999%の時の10年後の残高は
200423.1361654335円です。
よって、10年後の残高が2.0倍になる最低の金利は7.19999999999999%です。

コメント
while文にはいる前にinterestを0.1にする方法もあります。
その場合、
interest=interest+0.1;
を、while文で繰り返すブロックの最後に置くことになりますが、
そうすると、最後の表示で金利が0.1ずれます。



練習3-7
練習3-1で作ったプログラム中の繰り返しの不変量は何かを考え、
正しいことを確認せよ。
解答例
省略。


練習3-8
上のプログラムを拡張して、
金利が、10年以上のとき 0.45%, 7年以上のとき 0.4%, 5年以上のとき
0.3%, 4年以上のとき 0.25%, 3年以上のとき 0.23%, それ未満のとき 0.2%
で計算するようにプログラムを直し、1年間〜10年間預けた後の残高を
計算してみよ。
解答例(佐々木俊也さん)
class multiInterest { //複雑な条件
  public static void main(String[] arg){
    double interest1=1.002; //3年未満の金利
    double interest2=1.0023; //3年以上4年未満の金利
    double interest3=1.0025; //4年以上5年未満の金利
    double interest4=1.003; //5年以上7年未満の金利
    double interest5=1.004; //7年以上10年未満の金利
    double interest6=1.0045; //10年以上の金利
    int years=10; //預ける期間の最大値
    int year; //預ける期間
    double interest;  //預ける期間に対応した金利
    int currentyear; //何年目かを数える変数
    double principal=100000; //元金
    double balance; //残高
    for(year=1;year<=years;year=year+1){
      if (year >=10){
        interest=interest6;
      }
      else if(year>=7){
        interest=interest5;
      }
      else if(year>=5){
        interest=interest4;
      }
      else if(year>=4){
        interest=interest3;
      }
      else if(year>=3){
        interest=interest2;
      }
      else{
        interest=interest1;
      }
      balance=principal;
      // ここまでがそれぞれのyearにおける初期化処理
      for(currentyear=1;currentyear<=year; currentyear=currentyear+1){
        balance=balance*interest;
      }
      System.out.println(year+"年後の残高は"+balance+"円です。");
    }
  }
}

実行結果
1年後の残高は100200.0円です。
2年後の残高は100400.4円です。
3年後の残高は100691.5882167円です。
4年後の残高は101003.75625390623円です。
5年後の残高は101509.02704052425円です。
6年後の残高は101813.55412164581円です。
7年後の残高は102833.82489815327円です。
8年後の残高は103245.16019774588円です。
9年後の残高は103658.14083853686円です。
10年後の残高は104592.22715798837円です。

コメント
これは、預ける期間があらかじめ分かっている場合です。
これとは逆に、3年未満の時はその後10年預けても、
そのときの利子を0.2%で計算する場合は以下のようになります。

class multiInterest2 { //複雑な条件
  public static void main(String[] arg){
    double interest1=1.002; //3年未満の金利
    double interest2=1.0023; //3年以上4年未満の金利
    double interest3=1.0025; //4年以上5年未満の金利
    double interest4=1.003; //5年以上7年未満の金利
    double interest5=1.004; //7年以上10年未満の金利
    double interest6=1.0045; //10年以上の金利
    int years=10; //預ける期間の最大値
    int year; //預ける期間
    double interest;  //預ける期間に対応した金利
    int currentyear; //何年目かを数える変数
    double principal=100000; //元金
    double balance; //残高
    for(year=1;year<=years;year=year+1){
      balance=principal;
      // ここまでがそれぞれのyearにおける初期化処理
      for(currentyear=1;currentyear<=year; currentyear=currentyear+1){
        if (currentyear >=10){
          interest=interest6;
        }
        else if(currentyear>=7){
          interest=interest5;
        }
        else if(currentyear>=5){
          interest=interest4;
        }
        else if(currentyear>=4){
          interest=interest3;
        }
        else if(currentyear>=3){
          interest=interest2;
        }
        else{
          interest=interest1;
        }
        balance=balance*interest;
      }
      System.out.println(year+"年後の残高は"+balance+"円です。");
    }
  }
}

実行結果
1年後の残高は100200.0円です。
2年後の残高は100400.4円です。
3年後の残高は100631.32092円です。
4年後の残高は100882.8992223円です。
5年後の残高は101185.54791996688円です。
6年後の残高は101489.10456372677円です。
7年後の残高は101895.06098198167円です。
8年後の残高は102302.6412259096円です。
9年後の残高は102711.85179081323円です。
10年後の残高は103174.05512387189円です。



練習3-9
ある年yearが閏年かどうかのメッセージを表示するプログラムを
(1)1つのif文の条件式を
&& (かつ) / || または / ! (否定)の
組み合わせによって、(2)値の比較だけをする条件式を持つif文の
組み合わせでそれぞれ作れ。
ただし、西暦年が4の倍数でない年、または
西暦年が100の倍数かつ400の倍数でない年は
平年であり、それ以外の年は閏年である。
解答例(佐々木俊也さん)
class leapyear{ //条件の組み合わせ(1)
  public static void main(String[] args){
    int year=2000; //閏年かどうか判定すべき年
    if(year%4!=0||year%100==0&&year%400!=0){
      System.out.println(year+"年は閏年ではありません。");
    }
    else{
      System.out.println(year+"年は閏年です。");
    }
  }
}

class leapyear2{ //条件の組み合わせ(2)
  public static void main(String[] args){
    int year=2000; //閏年かどうか判定すべき年
    boolean leap; //閏年であればtrue そうでなければfalse
    if(year%4==0){
      if(year%100==0){
        if(year%400==0){
          leap=true; //400の倍数なら閏年
        }
        else {
          leap=false; //100の倍数だが400の倍数でなければ閏年でない
        }
      }
      else{
        leap=true; //4の倍数だが100の倍数でなければ閏年
      }
    }
    else{
      leap=false; //4の倍数でなければ閏年
    }
    if(leap==true){
      System.out.println(year+"年は閏年です。");
    }
    else{
      System.out.println(year+"年は閏年ではありません。");
    }
  }
}

実行結果(両方とも)
2000年は閏年です。

コメント
if文での条件判断は、「等しい」の場合==を使わないと、
正確に実行されません。
もし=を使った場合、代入とみなされ、
条件は常に成立ということになってしまいます。

また、両者を比較すると短いのは前者ですが、
条件が分かりやすいのは後者だと思います。