Ex06

From Prog0

Jump to: navigation, search

演習第6回

Contents

演習問題

主な内容

  • forループ
  • break/continue

以下の問題を解いて期限内に解答を提出してください。

出席確認

演習時間中に出席確認をLMS上の「演習出欠」で行ってください。出席確認用のパスワードは演習時間のどこかのタイミングで提示されます。


A問題

A-1 forループによる3の倍数の和の計算

ファイル名: ex06a1.c

下のプログラムは、キーボードから読み込んだ整数以下で、3 の倍数となるすべての正の整数の和を計算するものです。
for文中の (初期化;条件式;カウンター変数の更新)、if文中の条件判断をそれぞれ適切な式に修正し、プログラムを完成させなさい。

#include <stdio.h>
 
int main()
{
  int n, sum = 0;
  int i;
 
  printf("整数を入力して下さい:");
  scanf("%d", &n);
  
  for(初期化; 条件式; カウンター変数の更新){
    if( 3の倍数の条件判断 ){
      sum += i ;
    }
  }
  printf("%d以下で3の倍数となる正の整数の和は%dです\n", n, sum);

  return 0;
}

実行例

% ./a.out
整数を入力して下さい:50
50以下で3の倍数となる正の整数の和は408です
% ./a.out
整数を入力して下さい:51
51以下で3の倍数となる正の整数の和は459です

A-2 break, continueの利用

ファイル名: ex06a2.c

ある試験の点数のリストがあるとする。試験の点数は0点から100点とする。点数のリストをキーボードから読み込み、決まった範囲にある答案の枚数をカウントしたい。 以下のプログラムで足りない部分を補ってプログラムを完成させなさい。

  • カウントする点数の範囲は50点(変数"L")以上、80点(変数"U")未満とする。この場合に該当する答案の枚数をカウントする。
  • カウントする変数は"count"とすること。
  • continue文, break文を使うこと。
  • 負の数が入力されたら、ループを終了すること。
  • forループ内の「必要な処理」以外の部分を変更してはいけない。

#include <stdio.h>
 
int main()
{
  int i;
  int count;
  int score;

  int L = 50;
  int U = 80;
 
  count = 0;
  printf("点数を入力して下さい\n");   
  for(i = 0; i < 15; i++){
    scanf("%d", &score);  

    /* この部分に必要な処理を追加してください */

    count++;
  }

  printf("%d点以上、%d点未満の答案の数は%dです\n", L, U, count);
 
  return 0;
}

実行例

% ./a.out
点数を入力して下さい 
51
-1
50点以上、80点未満の答案の数は1です 
% ./a.out
点数を入力して下さい 
10
20
30
-1
50点以上、80点未満の答案の数は0です
% ./a.out
点数を入力して下さい 
33
55
83
92
60
-1
50点以上、80点未満の答案の数は2です

B問題

B-1 階乗の計算

ファイル名: ex06b1.c

入力された正の整数の階乗を出力するプログラムを作成しなさい。ただし、以下の条件を全て満たす必要がある。

  • ループは forループのみを使いなさい。
  • for 文のカウンタ変数はデクリメントしなさい。
  • 入力された整数が 13 以上だと正しく計算できないので、負または 13 以上の数が入力されたら「計算できません」と表示して終了すること。

正の整数 n の階乗とは 1 から n までの整数をすべて掛け合わせたものであり、n! と表す(例:5の階乗は 5! = 5×4×3×2×1 = 120 となる)。ただし、ゼロの階乗は 0! = 1 と定義されている。

% ./a.out
階乗を計算したい数を入力してください:5
120
% ./a.out
階乗を計算したい数を入力してください:12
479001600
% ./a.out
階乗を計算したい数を入力してください:30
計算できません
% ./a.out
階乗を計算したい数を入力してください:0
1
%

計算するときには、誤って 0 をかけ算すると結果が常に 0 になってしまうことに注意すること。

B-2 「組み合わせ」の計算

ファイル名: ex06b2_1.c, ex06b2_2.c

異なる n 個のものから順序を考えずに r 個のものを取り出すときの場合の数を「n 個のものから r 個をとる組み合わせ」と言い、nCr で表す。この数は、

nCr = n! / (n-r)!r!  (但し、0≦r≦n)

と定義されている。この数を計算するプログラムを作成しなさい。

まず、以下の方法で計算するプログラムを作り、ex06b2_1.c として提出しなさい。

  1. n と r を入力させる。
  2. n! を計算する (ヒント: B-1 を参照せよ)
  3. (n-r)! を計算する
  4. r! を計算する
  5. (2) / (3) / (4) を計算する

一方、 n! と (n-r)! は一部が重複していて、重複部分は 5. の割り算で相殺されるため、計算を省略することができる。このようにして計算の手間を省いたプログラムを作り、ex06b2_2.c として提出しなさい。また、12C5などを計算して、2つのプログラムで同じ結果が得られることを確認しなさい。

なお、いずれのプログラムでも入力された n と r の値が適切かどうかはチェックしなくてよい。


実行例 (ex06b2_1.c でも ex06b2_2.c でも同じ結果になる)

% ./a.out
nとrを入力してください:12 5
12C5 = 792
% ./a.out
nとrを入力してください:10 5
10C5 = 252
% ./a.out
nとrを入力してください:3 1
3C1 = 3
% ./a.out
nとrを入力してください:5 0
5C0 = 1
%

ex06b2_2.c へのヒント: 例えば上の例で、n を 12、r を 5 としたとき、nCr の計算で行う 12! (=n! ) の 7! (=(n-r)! ) による割り算は 12×11×10×9×8 に等しい。

B-3 利子の複利計算

ファイル名: ex06b3.c

ある人が友人に 1 万円の借金をしました。しかしその友人は、「1ヶ月ごとに p (%) の利子をつける」と言ってきました。 各月に生じる利子は借金に加算され、その次の月の元金に含まれるものとします(1円未満の端数は切り捨て)。 p と n をキーボードから入力して、n ヶ月後の借金額を出力するプログラムを作成しなさい。 なお、プログラムでは while ループではなく、for ループを使用すること。

(注1)利率がパーセント表示なので、毎月発生する利子は「その月の元金 × 利率(%)/100」となります。

(注2)計算方法によって、計算額は多少(数円程度)誤差が出ることがあります。実行例から数円程度のずれであれば問題はありません。

% ./a.out
利率と期間を整数で入力して下さい:1 1
1ヶ月後の借金は 10100円です
% ./a.out
利率と期間を整数で入力して下さい:5 6
6ヶ月後の借金は 13399円です
% ./a.out
利率と期間を整数で入力して下さい:6 12
12ヶ月後の借金は 20115円です
%

利息の計算法(単利と複利)について

利息を計算するときに、当初の元金に対してだけ利息がつく方式を単利といいます。 これに対し、利息を元金に繰り入れて、元金と利息の合計額に対して次期の利息がつく方式を複利といいます。今回の問題では、こちらの複利方式での計算が課題になっています。

最初の一期間の利息は単利・複利どちらでも同じですが、二期間目以降になると、複利計算では元金に加えてそれまでの利息に対してもさらに利息が計算されるので、合計が大きくなります。 そのため、直感的な予想に比べて計算結果が大きすぎるように感じるかもしれません。

一期間後の合計:

元金 + 元金×利率 = 元金×(1 + 利率)   注:利率が%単位の場合は前もって1/100倍しておきます。

二期間後の合計:

単利の場合 元金×(1 + 利率×2)

複利の場合 元金×(1 + 利率)×(1 + 利率)

三期間後の合計:

単利の場合 元金×(1 + 利率×3)

複利の場合 元金×(1 + 利率)×(1 + 利率)×(1 + 利率)

当初元金10000円の借金に、年利10%で利息を加えた金額の比較
毎年の利子(単利) 単利の場合の合計 毎年の利子(1年複利) 複利の場合の合計
開始時 10000円 10000円
1年後 1000円 11000円 1000円 11000円
2年後 1000円 12000円 1100円 12100円
3年後 1000円 13000円 1210円 13310円
4年後 1000円 14000円 1331円 14641円
5年後 1000円 15000円 1464円 16105円

この例から分かるように、時間が経つほど、単利と複利の利息の差は大きくなります。 (今回の課題では一月毎に利子を計算していますが、上の例はより一般的な、1年を一期間とした計算例になっています。)


余談:72の法則

複利計算で、元金と利息の合計が当初の2倍になる利率・期間の大ざっぱな目安として、72の法則(あるいは70の法則)というものが知られています。これは、

一期間当たり利率(%) × 期間の長さ = 70から72程度

となる期間で合計金額が当初の元金のほぼ倍になる、というものです。 例えば、月6%複利で12ヶ月借りていると 6 × 12 = 72 ですから、借金が(1.72倍ではなく)約2倍になると予想できます。実際に今回の課題のプログラムを実行してみると、この予想が正しいことが分かります。 なお、月6%複利で24ヶ月なら、(2倍の2倍で)ほぼ4倍になります。

Extra問題

E-1 素数判定

ファイル名: ex06e1.c

以下の仕様に従ってプログラムを作成しなさい。

  • for ループを使って、整数の入力を5回行う。
  • それぞれの入力された整数について、それが素数がどうかを for ループを使って判定する。
  • ただし、入力された整数が負の数, 0, 1 の場合には素数判定をしない。
  • 素数判定のアルゴリズムは「整数 n について、 2 から n-1 までの全ての整数で割り切れない場合、n は素数と判定」とする。
  • 実行例のように、全入力終了後に素数の総数を出力すること。

[実行例1]

% ./a.out
1個目の整数を入力してください:-1
入力は正の整数にしてください
2個目の整数を入力してください:1
入力された整数が 1 なのでスキップします
3個目の整数を入力してください:2
2 は素数
4個目の整数を入力してください:3
3 は素数
5個目の整数を入力してください:4
素数は 2 個ありました
%

[実行例2]

% ./a.out
1個目の整数を入力してください:51
2個目の整数を入力してください:53
53 は素数
3個目の整数を入力してください:55
4個目の整数を入力してください:57
5個目の整数を入力してください:59
59 は素数
素数は 2 個ありました
%

[実行例3]

% ./a.out
1個目の整数を入力してください:211
211 は素数
2個目の整数を入力してください:277
277 は素数
3個目の整数を入力してください:311
311 は素数
4個目の整数を入力してください:433
433 は素数
5個目の整数を入力してください:499
499 は素数
素数は 5 個ありました
%

課題提出上の注意事項

解答ファイルはmenuコマンドを使って提出してください。以下のようにmenuコマンドを実行し、表示されるメッセージに沿って操作すること。

% ~prog0/bin/menu

menuコマンドは、解答ファイルが ~/Prog0/Ex## のディレクトリに指定されたファイル名で置かれているものとして処理します。正常に提出された場合は ○ が、何らかのエラーが生じた場合は × が表示されます。

解答の提出期間は以下のとおりです。

問題提出受付開始提出〆切
A問題 演習日の6日前の午後9時演習終了時刻
B, Extra問題 演習日の6日前の午後9時演習日の6日後の午後9時

提出は〆切前であれば何度でもやり直すことができます。再提出すると、前に提出したファイルは新しい内容で上書きされます。

Personal tools