プログラミング技法 演習 1 演習 1 1 数値計算の基礎 演習 実習 1 1 以下のプログラムを実行し, 結果がプログラムの意図通りのものか確認せよ. 1:#include <stdio.h> 2:int main() 3:{ 4: double x = 0; 5: int i; 6: for (

Similar documents
Microsoft Word - NumericalComputation.docx

char int float double の変数型はそれぞれ 文字あるいは小さな整数 整数 実数 より精度の高い ( 数値のより大きい より小さい ) 実数 を扱う時に用いる 備考 : 基本型の説明に示した 浮動小数点 とは数値を指数表現で表す方法である 例えば は指数表現で 3 書く

Taro-リストⅠ(公開版).jtd

関数の呼び出し ( 選択ソート ) 選択ソートのプログラム (findminvalue, findandreplace ができているとする ) #include <stdio.h> #define InFile "data.txt" #define OutFile "sorted.txt" #def

プログラミング方法論 II 第 14,15 回 ( 担当 : 鈴木伸夫 ) 問題 17. x 座標と y 座標をメンバに持つ構造体 Point を作成せよ 但し座標 は double 型とする typedef struct{ (a) x; (b) y; } Point; 問題 18. 問題 17 の

関数の呼び出し ( 選択ソート ) 選択ソートのプログラム (findminvalue, findandreplace ができているとする ) #include <stdiu.h> #define InFile "data.txt" #define OutFile "surted.txt" #def

Microsoft PowerPoint - 説明2_演算と型(C_guide2)【2015新教材対応確認済み】.pptx

kiso2-09.key

Taro-数値計算の基礎Ⅱ(公開版)

ゲームエンジンの構成要素

kiso2-06.key

プログラミング基礎

<4D F736F F D20438CBE8CEA8D758DC F0939A82C282AB2E646F63>

Microsoft PowerPoint - 4.pptx

プログラミング基礎

C プログラミング演習 1( 再 ) 2 講義では C プログラミングの基本を学び 演習では やや実践的なプログラミングを通して学ぶ

Microsoft PowerPoint - kougi9.ppt

PowerPoint プレゼンテーション

gengo1-11

PowerPoint Presentation

プログラミング実習I

演習課題No12

Taro-スタック(公開版).jtd

CプログラミングI

cp-7. 配列

問 2 ( 型変換 ) 次のプログラムを実行しても正しい結果が得られない 何が間違いかを指摘し 正しく修正せよ ただし int サイズが 2 バイト long サイズが 4 バイトの処理系での演算を仮定する #include <stdio.h> int main( void ) { int a =

情報処理演習 B8クラス

gengo1-2

Microsoft PowerPoint - kougi2.ppt

2006年10月5日(木)実施

Prog1_12th

Microsoft PowerPoint - program.ppt [互換モード]

Prog1_6th

計算機シミュレーション

gengo1-10

Microsoft Word - no11.docx

PowerPoint プレゼンテーション

Microsoft PowerPoint - kougi4.ppt

PowerPoint プレゼンテーション

Microsoft PowerPoint - 06.pptx

スライド 1

Microsoft PowerPoint - lec10.ppt

PowerPoint プレゼンテーション

kiso2-03.key

Microsoft PowerPoint - C1(演算と変数).ppt

NumericalProg09

memo

Microsoft Word - Cプログラミング演習(3)

PowerPoint プレゼンテーション

Chap3.key

データ構造

Microsoft Word - 3new.doc

1. 関数 scanf() 関数 printf() は変数の値を画面に表示しますが それに対し関数 scanf() はキーボードで入力した値を変数に代入します この関数を活用することで対話式 ( ユーザーの操作に応じて処理を行う ) プログラムを作ることができるようになります 整数の和

C 言語第 6 回 1 数値シミュレーション :2 階の微分方程式 ( シラバス10 11 回目 ) 1 2 階の微分方程式と差分方程式微分方程式を 2 d x dx + c = f ( x, t) 2 dt dt とする これを 2 つの 1 階の微分方程式に変更する ìdx = y 2 2 d

PowerPoint プレゼンテーション

Microsoft PowerPoint - prog06.ppt

2014計算機実験1_1

Microsoft PowerPoint - lec4.ppt

Microsoft Word - no15.docx

Microsoft PowerPoint - prog04.ppt

モデリングとは

パソコンシミュレータの現状

スライド 1

情報実習Ⅱ

Microsoft PowerPoint - 説明3_if文switch文(C_guide3)【2015新教材対応確認済み】.pptx

Taro-ファイル処理(公開版).jtd

Microsoft PowerPoint - prog08.ppt

重要例題113

演算増幅器

バイオプログラミング第 1 榊原康文 佐藤健吾 慶應義塾大学理工学部生命情報学科

Microsoft Word - no103.docx

講習No.9

Microsoft Word - Training10_プリプロセッサ.docx

Prog1_6th

/*Source.cpp*/ #include<stdio.h> //printf はここでインクルードして初めて使えるようになる // ここで関数 average を定義 3 つの整数の平均値を返す double 型の関数です double average(int a,int b,int c){

Microsoft PowerPoint - 第3回目.ppt [互換モード]

<4D F736F F F696E74202D20836F CC8A C58B858B4F93B982A882E682D1978E89BA814091B28BC68CA48B E >

Microsoft PowerPoint - 計算機言語 第7回.ppt

Microsoft PowerPoint - 12.ppt [互換モード]

数値計算

C 言語第 3 回 2 a と b? 関係演算子 a と b の関係 関係演算子 等しい a==b 等しくない a!=b より大きい a>b 以上 a>=b より小さい a<b 以下 a<=b 状態 真偽 値 条件が満たされた場合 TRUE( 真 ) 1(0 以外 ) 条件が満たされなかった場合 F

講習No.10

Microsoft Word - 微分入門.doc

4-4 while 文 for 文と同様 ある処理を繰り返し実行するためのものだが for 文と違うのは while 文で指定するのは 継続条件のみであるということ for 文で書かれた左のプログラムを while 文で書き換えると右のようになる /* 読込んだ正の整数値までカウントアップ (for

Microsoft Word - Cプログラミング演習(12)

Taro-再帰関数Ⅲ(公開版).jtd

次に示す数値の並びを昇順にソートするものとする このソートでは配列の末尾側から操作を行っていく まず 末尾の数値 9 と 8 に着目する 昇順にソートするので この値を交換すると以下の数値の並びになる 次に末尾側から 2 番目と 3 番目の 1

Microsoft Word - Cプログラミング演習(8)

Taro-プログラミングの基礎Ⅱ(公

Microsoft PowerPoint - C言語の復習(配布用).ppt [互換モード]

プログラミング基礎

1999年度 センター試験・数学ⅡB

Microsoft PowerPoint - prog11.ppt

Microsoft PowerPoint - C_Programming(3).pptx

P02.ppt

Taro-リストⅢ(公開版).jtd

4 月 東京都立蔵前工業高等学校平成 30 年度教科 ( 工業 ) 科目 ( プログラミング技術 ) 年間授業計画 教科 :( 工業 ) 科目 :( プログラミング技術 ) 単位数 : 2 単位 対象学年組 :( 第 3 学年電気科 ) 教科担当者 :( 高橋寛 三枝明夫 ) 使用教科書 :( プロ

プログラミングI第10回

£Ã¥×¥í¥°¥é¥ß¥ó¥°(2018) - Âè11²ó – ½ÉÂꣲ¤Î²òÀ⡤±é½¬£² –

新版明解C言語入門編

Transcription:

プログラミング技法 演習 1 演習 1 1 数値計算の基礎 演習 実習 1 1 以下のプログラムを実行し, 結果がプログラムの意図通りのものか確認せよ. 1:#include <stdio.h> 2:int main() 3: 4: double x = 0; 5: int i; 6: for (i = 0; i < 100; i++) 7: x += 0.1; 8: 9: printf("%2.15lf\n", x); 10: return 0; 11: 実習 1 2 以下のプログラムを入力実行せよ. 次に, 途中の計算順を d = a - c; e = d + b; として同様に実行せよ. さらに, この 2 つの結果の差違について原因を考えよ. 1:#include <stdio.h> 2:int main() 3: 4: double a = 1234e10, b = 2e-4; 5: double c = 1233e10, d,e; 6: d = a + b; 7: e = d - c; 8: printf("%.4lf\n",e); 9: return 0; 10: 実習 1 3 教材プリントの問題 1 2,1 3 のプログラムを実行し結果を確認せよ.

演習 2 1 計算機の基礎 実習 1 4 以下のプログラムは 10 進数を 2 進数に変換するためのプログラムである. 1:#include <stdio.h> 2: 3:int main() 4: 5: int dec, work,i; 6: char bin[8]; 7: 8: printf("0 255 の値を入力 :"); 9: scanf("%d",&dec); 10: work = dec; 11: for (i = 0; i < 8; i++) 12: if (work % 2!= 0) 13: bin[i] = '1'; 14: else 15: bin[i] = '0'; 16: 17: work /= 2; 18: 19: printf("%d = ",dec); 20: for (i = 7; i >= 0; i--) 21: printf("%c",bin[i]); 22: 23: printf("\n"); 24: 1. プログラムを実行し, 適当な値を入力し動作を確認せよ. 2. ( やや難 ) 上記のプログラムを参考に小数の 10 進数を 2 進数に変換するプログラムを作成せよ.(2 進数は小数点以下 15 桁程度とし, それ以下は無視してよい ) 3. 作成したプログラムを用いて,10 進の 0.1 が授業で説明したような値になるか確認せよ.

プログラミング技法 演習 1 演習 3 演習 1 解説, プログラム例 実習 1 1 以下の実行結果の例のように正確に 1.0 になることはありません.( 実行環境により結果は若干変る場合があります.) 実行結果例 9.999999999999980 実習 1 2 実行結果の例を以下に示します. 実行結果例 ( 変更前 ) 10000000000.0000 実行結果例 ( 変更後 ) 10000000000.0002 解説 変更前の計算は (1234 10 10 + 2 10 4 ) 1233 10 10 であり, 括弧の計算は情報落ちの誤差により 1234 10 10 となります. 結果として計算は 1234 10 10 1233 10 10 となります. 変更後は (1234 10 10 1233 10 10 ) + 2 10 4 となり, 結果として計算内容は, 1 10 10 + 2 10 4 となり左の項の桁が下がります. このため, 情報落ちの誤差が発生しない演算となり, 正しい結果が得られることになります. 上記のように計算順によっても, 各種誤差が発生する場合としない場合があり, 精密な計算をする場合は計算順にも気を使う必要があります. 実習 1 3 プログラムのみを示します. 問題 1-2 のプログラム 1:#include <stdio.h> 2:int main() 3: 4: int sum = 0,i; 5: for (i = 1; i <= 100; i++) 6: sum += i; 7: 8: printf("%d\n", sum); 9: return 0; 10:

演習 4 1 計算機の基礎 問題 1-3 のプログラム 1:#include <stdio.h> 2:int main() 3: 4: int a,b,c,i; 5: a = 1; b = 2; 6: for (i = 3; i<=6; i++) 7: c = 2 * a + b; 8: a = b; b = c; 9: 10: printf("%d", c); 11: return 0; 12: 実習 1 4 2. のプログラムのみ示します. 1:#include <stdio.h> 2:#define N 20 // 小数点以下の桁数 3:int main() 4: 5: double dec, work; 6: int i; 7: char bin[n]; 8: printf("0 1 の間の小数を入力 "); 9: scanf("%lf",&dec); 10: work = dec; 11: for (i = 0; i < N; i++) 12: work *= 2; 13: if (work >= 1) 14: bin[i] = '1'; 15: work -= 1; 16: else 17: bin[i] = '0'; 18: 19: 20: printf("%f = 0.",dec); 21: for (i = 0; i < N; i++) 22: printf("%c",bin[i]); 23: 24: return 0; 25:

プログラミング技法 演習 2 演習 5 2 方程式 f(x) = 0 の解法 演習 実習 2 1 二分法による f(x) = 0 の解の導出について. 1 1. 教材プリント 10 ページの問題 2 2 の, 結果を確認せよ. また, 下に示したように, 計算途中の a,b,c,f(c) の値を表示できるようプログラムを修正し, 二分法による計算の様子を確認せよ. 2. プログラムは関数が右肩下りの場合でも正常に解を求めることができる. 目的関数を sin x, 初期値を a = 3, b = 5 として, 実行し動作を確認せよ. a b c func(c) 3.00000 5.00000 4.00000-0.75680 3.00000 4.00000 3.50000-0.35078 略 3.14154 3.14160 3.14157 0.00002 答えは 3.141571 です. 実習 2 2 ニュートン法のプログラムについて. 1. 教材プリント 15 ページの問題 2 4 のプログラムを実行し確認せよ. また, 計算途中の x n, x n+1 を表示できるよう, プログラムを修正し, 実行確認せよ. 2. ニュートン法のプログラムは, 初期値が解と離れ過ぎていると, 収束しない場合がある. 以下の 3 次方程式を初期値を 2 として計算を行え. この場合, ニュートン法では解に収束しないことを確認せよ.( プログラムは 1. で修正した途中経過が見えるものを用いよ ) x 3 3x 2 x + 7 = 0 3. 一定回数 (20 回程度 ) 繰り返し計算をしても終了条件を満たさない場合, 画面に 収束しませんでした と表示し終了するように修正せよ. また,2. の式を用いて, 動作を確認せよ. 1 以下の演習は終端条件 ε = 1.0 10 8 程度として行うこと

演習 6 実習 2 3 ニュートン法は解を求めたい関数の導関数を予め求めておく必要があり, やや手間が増えることが難点である. この点を回避するための計算方法として, 割線法と呼ばれる方法がある. 図のように, 点 P 1, P 2 の 2 点を通る直線を接線の近似線として, ニュートン法と同様の処理を行う方法である. y f(x 1 ) f(x 2 ) 2 方程式 f(x) = 0 の解法 y = f(x) P 1 P 2 1. P 1, P 2 を通る直線の方程式を求める. 以下の空白を埋めよ. x 3 x 2 x 1 x 直線の傾き m は m = ある点 (x p, y p ) を通る傾き m の直線は y y p = m(x x p ) で表わされる. これより, 点 P 1 を通る直線の方程式を求めよ. y = この結果より,x 1, x 2 から x 3 を求める式を求めよ. また,x n 2, x n 1 より,x n を求める式を求めよ. x 3 = 2. 上記の内容を参考に x n 2, x n 1 より,x n を求める式を求めよ. x n = 3. f(x) を問題 2 4 の x + log x, 初期値を x 1 = 2, x 2 = 1.8 として,x 10 を計算せよ.(Excel を用いると簡単にできる ) 4. 割線法の考え方を用い,3. と同様の条件で x + log x = 0 の解を求めるプログラムを作成, 実行せよ.

プログラミング技法 演習 2 演習 7 実習 2 4 ( やや難 ) 複数の解を自動的に求めるようなプログラムを作成する. 1. 二分法の部分を関数化せよ. 下に示したような形の関数として,a,b には二分法に必要な初期値, 返り値は f(x) = 0 の解となるように関数を作成せよ. なお, 求める関数は別に f という名前で定義されているものとする. double solve(double a, double b) 2. ある y = f(x) の区間 (x, x+dx) の間に f(x) = 0 の解 x 0 が存在する場合,f(x)f(x+dx) < 0 の関係が成り立つ. 以下の手順により, 指定した区間 (x s, x e ) の間にある, 解が, おおよそどこにあるのか調べることができる. (a) 調査区間 (x s, x e ), 調査間隔 dx を指定 (b) f(x)f(x + dx) の符号をチェック 0 以下だったら何らかのメッセージを表示 正ならなにもしない (c) x x + dt として,x が x e になるまで 2 へもどる この手順に従ったプログラムを作成し実行せよ. 関数と調査区間は適当なものを選ぶこと.( 例えば,(x 1)(x 3)(x + 1), 区間は ( 5, 5) など ) 3. (1) の二分法による求解関数と,(2) の解の存在確認のプログラムを組合せて, 区間を指定したら, その区間の関数 f(x) = 0 の解を自動的に計算, 表示するようなプログラムを作成せよ.

演習 8 2 方程式 f(x) = 0 の解法 Memo

プログラミング技法 演習 2 演習 9 演習 2 解説, プログラム例 実習 2 1 略 実習 2 2 2. 以下のような計算を繰り返し, 値は収束しない. x_n x_n+1 2.000000 3.000000 3.000000 2.500000 2.500000 2.000000 2.000000 3.000000 3.000000 2.500000 2.500000 2.000000 2.000000 3.000000 3.000000 2.500000... 3 プログラム例を以下に示す.cnt という変数を用いて計算回数を記憶し, 規定回数を超えたら break 文で終了するようにしてあります. #include <stdio.h> #include <math.h> #define EPS 1.0e-8 // 終端条件の値 double f(double); // 対象関数 double df(double); // f(x) の導関数 int main(void) double x0, x1; int cnt = 0; x0=2; // 初期値の設定 while(1) // 無限に繰り返します x1 = x0 - f(x0) / df(x0); printf("%f %f\n", x0,x1); if (fabs(f(x1)) < EPS) // 終端条件 printf(" 解は %f です.\n", x1); break; else if (cnt > 20) // 非収束の場合 printf(" 収束しませんでした \n"); break; 以下略 cnt++; x0 = x1; // 求めた x1 を次は x0 とする 実習 2 3 1. P 1 と P 2 を通る直線の傾き m = f(x 2) f(x 1 ) x 2 x 1 直線の方程式 y = f(x 2) f(x 1 ) x 2 x 1 (x x 1 ) + f(x 1 ) 2. x n と x n 1, x n 2 の関係式 x 3 = x 1f(x 2 ) x 2 f(x 1 ) f(x 2 ) f(x 1 ) x n = x n 2f(x n 1 ) x n 1 f(x n 2 ) f(x n 1 ) f(x n 2 ) 4. 割線法によるプログラムニュートン法のプログラムと異なり, 導関数 f は必要ありません. /* 割線法による f(x)=0 の解を求める */ #include <stdio.h> #include <math.h> #define EPS 1.0e-8 // 終端条件の値 double f(double); // 対象関数 int main(void) double x0, x1, x2; int cnt = 0; x0 = 2; x1 =1.8;// 初期値の設定 while (true) x2 = x1 - (x1 - x0) / (f(x1) - f(x0))*f(x1); //printf("%f %f %f\n",x1,f(x1),x2); if (fabs(f(x1)) < EPS) // 終端条件 printf("x = %f\n", x1); break; else if (cnt >= 10) printf(" 収束しませんでした."); break; x0 = x1; x1 = x2; cnt++; return 0; double f(double x) return x + log (x); // 求めた x1 を次は x0 とする

演習 10 2 方程式 f(x) = 0 の解法 実習 2 4 1. 二分法による求解関数 double solve(double a, double b) double c; while(1) // 無条件に繰り返し続けます c = (a + b) / 2; if (f(c)*f(a) < 0) b = c; if (f(c)*f(b) < 0) a = c; if (fabs(f(c)) < EPS) break; return c; 2. 解の探索プログラム #include <stdio.h> double f(double x); int main() double x_s, x_e, x, dx; scanf("%lf %lf %lf", &x_s, &x_e, &dx); for (x = x_s; x <= x_e; x += dx) if (f(x) * f(x+dx) < 0) printf("%f - %f の間に解あり \n",x, x+dx); return 0; double f(double x) return (x-3)*(x-1)*(x+3); 3. 自動求解プログラム #include <stdio.h> #include <math.h> #define EPS 1.0e-8 double f(double x); double solve(double a, double b); int main() double x_s, x_e, x, dx, x0; printf(" 開始点, 終了点, 刻み幅 "); scanf("%lf %lf %lf", &x_s, &x_e, &dx); for (x = x_s; x <= x_e; x += dx) if (f(x) * f(x+dx) < 0) x0 = solve(x, x+dx); printf(" 解 :%f\n",x0); return 0; double solve(double a, double b) double c; for (;;) // 無条件に繰り返し続けます c = (a + b) / 2; if (f(c)*f(a) < 0) b = c; if (f(c)*f(b) < 0) a = c; if (fabs(f(c)) < EPS) break; return c; double f(double x) return (x-3)*(x-1)*(x+3);

プログラミング技法 演習 3 演習 11 3 曲線の積分 演習 実習 3 1 長方形の和, 台形則, シンプソン法の 3 つの手法により積分を求めよ. なお, 積分区間を 40 分割して近似計算を行うこと. (1) (2) 5 1 π 0 (x 3 9x 2 + 23x 15) dx (= 0) sin tdt (= 2) 実習 3 2 シンプソン法は曲線を曲線上の 3 点を通る 2 次曲線で近似を行い, その近似曲線から得られる面積を, 面積の近似値として用いる. これに対して, 曲線上の 4 点を通る 3 次曲線で元の曲線を近似する方法が存在する. これはシンプソン法を拡張したもので,1 区画の面積 s k は s k = 3 x 8 (f(x k) + 3f(x k+1 ) + 3f(x k+2 ) + f(x k+3 )) s で表され,x 0 x n の面積 S は S = S 1 + S 4 + S 7 + として計算される 2. なお, この公式を用いる場合は区間の分割数は 3 の倍数である必要がある. この公式を用いて, 演習 3 1 の積分について計算を行え. 積分区間の分割数は 39 とすること. 2 2 次式で近似されたものをシンプソンの 1/3 則公式,3 次式で近似されたものをシンプソンの 3/8 則公式と区 別して呼ぶ場合がある.

演習 12 3 曲線の積分 実習 3 3 ある物体が, 下に示したグラフのように速度を変化させながら移動した. この物体の移動距離を考える. 移動距離はグラフ上の面積として表わされる. この計算を区分求積法により行なう. 1. 区間 t = 0 2 および区間 t = 2 4 における速度の式を求めよ. 2. 移動距離を計算せよ.( 区分求積ではなく, 一般的な方法で ) 3. 次のページのプログラムの空欄を埋め, 移動距離を区分求積によって求めるプログラムを完成せよ. v 2 1 0 2 4 t #include <stdio.h> double func(double); int main() double start = 0, end = 4; // 積分区間 double t, dt = 0.1; double s = 0; for (t = start; t < end; t += dt) (a) ; printf(" 移動距離は %.8f です.\n",s); return 0; double func(double t) // 移動速度の関数 double ret = 0; if ( (b) ) (c) ; else if ( (d) ) (e) ; return ret;

プログラミング技法 演習 3 演習 13 実習 3 4 真空中に 1µC の点電荷が存在する. この点電荷から 2m 離れた地点より,1m 離れた地点の電位差計算する. 1μC 1m 2m V[V] 1. 点電荷から r[m] 離れた地点での, 電解中から受ける力を示せ. 2. 求める値を導くための積分式を示せ. 3. 上記の結果に基づいて, シンプソン法を用いて, 積分値を算出せよ. なお, 積分間隔は x = 1cm とすること. 真空中の誘電率は ε 0 = 8.85410 12 とする. 実習 3 5 数値積分は積分区間を細かくするほど, 正確な積分値を求めることが出来る. 長方形の和, 台形公式, シンプソン法によって ln x を [1, e] の区間で積分したとき, 何分割すれば必要な精度が得えられるのか調べよ. 必要な精度はここでは, 真値に対して誤差が 1.0 10 4 以下であるものとして考えること. なお, 式中 ln x 関数は,C 言語では log(x) 関数を用いる.

演習 14 3 曲線の積分 実習 3 6 ( やや難 ) 積分により面積を求める場合, 図のような場合を考えると式は b a f(x) dx についての演算を行うこととなる. しかしシンプソン法などの区分求積法を用いると, 点 c 付近の正負の処理がいい加減になる場合が考えられる. これに関して,f(x) = 0 の点 c の値を正確に求め, c a f(x)dx + b c f(x)dx のような形で分割した積分を行う必要があると思われる. 上記のような考え方を元に, 自動的に x 軸と関数の交点を求め, 面積を求めるプログラムを作成する. 1. ( 実習 2 3 の 2. と同じです.) ある y = f(x) の区間 (x, x + dx) の間に f(x) = 0 の解 x 0 が存在する場合,f(x)f(x + dx) < 0 の関係が成り立つ. 以下の手順により, 指定した区間 (x s, x e ) の間にある, 解が, おおよそどこにあるのか調べることができる. (a) 調査区間 (x s, x e ), 調査間隔 dx を指定 (b) f(x)f(x + dx) の符号をチェック 0 以下だったら何らかのメッセージを表示 正ならなにもしない (c) x x + dt として,x が x e になるまで 2 へもどる 2. 1. の結果と以下の 2 つの関数を用いて面積を求めるプログラムを完成せよ. 3. また, 作成した面積計算プログラムを用い, 区間 [0:6] における f(x) = x 3 9x 2 + 23x 15 と x 軸とで囲まれた面積を求めよ. シンプソン法の求積関数 二分法による求解関数 double simpson(double st, double ed) double x, s = 0, h; int k, n = ((int)(10 * (ed - st)))*2; h = (ed - st) / n; for (k = 0; k < n; k += 2) x = st + h*k; s += h/3 * (fabs(f(x)) + 4 * fabs(f(x+h)) + fabs(f(x + h*2))); return s; double solve(double a, double b) double c; for (;;) // 無条件に繰り返し続けます c = (a + b) / 2; if (f(c)*f(a) < 0) b = c; if (f(c)*f(b) < 0) a = c; if (fabs(f(c)) < EPS) break; return c; Note! 関数 simpson の n = ((int)(10 * (ed - st)))*2; の式は刻み幅をおおよそ 0.05 程度にするための式です.

プログラミング技法 演習 3 演習 15 演習 3 解説, プログラム例 実習 3 1 計算結果を示します. 長方形の和 台形公式 シンプソン法 (1) -0.00000-0.00000 0.00000 (2) 1.99897 1.99897 2.00000 実習 3 2 ループ内のみ示します. for (k = 0; k < n; k += 3) s += 3*h/8 * (func(x) + 3*func(x+h) + 3*func(x+2*h) + func(x+3*h)); x += 3*h; 積分値は,(1) -0.00000, (2) 2.00000 実習 3 3 1. 以下の通り v = t (0 t 2) v = 3 t/2 (2 t 4) 2. 5 3. 空欄部分のみ示す. (a) s += dt * func(t) (b) t >= 0 && t < 2 (c) ret = t (d) t >= 2 && t < 4 (e) ret = 3-t/2 実習 3 4 電位の計算は,l[C] の電荷がクーロン力に逆らって動かす仕事なので, クーロン力は, F = Qq 4πε 0 r 2 であるから, 以下のような積分計算を行えばよいことになります. 1 Q V = 2 4πε 0 r 2 dr Q = 1[µC], ε 0 = 8.85410 12 とすると, 電位差は V = 4493.82[V] になります. 実習 3 5 おおよそ, 以下の分割数で精度が出でます. 長方形の和 : 8592 分割台形公式 : 40 分割シンプソン法 : 6 分割 実習 3 6 最終的なプログラムの例を示します. #include <stdio.h> #include <math.h> #define EPS 1e-10 double solve(double a, double b); double simpson(double s, double e); double f(double x); int main() double start, end, step; double x, x1, x2; double s = 0, ss; printf(" 初期値, 終端値, 間隔 "); scanf("%lf %lf %lf", &start, &end, &step); x1 = start; for (x = start; x < end; x += step) if (f(x) * f(x+step) < 0) x2 = solve(x, x+step); ss = simpson(x1,x2); printf("%f - %f 間の面積 =%f\n",x1,x2,ss); s += ss; x1 = x2; else if (x+step >= end) ss = simpson(x1,end); printf("%f - %f 間の面積 =%f\n",x1,end,ss); s += ss; printf(" 面積は %f\n", s); double solve(double a, double b) double c; for (;;) // 無条件に繰り返し続けます c = (a + b) / 2; if (f(c)*f(a) < 0) b = c; if (f(c)*f(b) < 0) a = c; if (fabs(f(c)) < EPS) break; return c; double simpson(double st, double ed) double x, s = 0, h; int k, n = ((int)(10 * (ed - st)))*2; h = (ed - st) / n; for (k = 0; k < n; k += 2) x = st + h*k; s += h/3 * (fabs(f(x)) + 4 * fabs(f(x+h)) + fabs(f(x + h*2))); return s; double f(double x) return x*x*x - 9*x*x + 23*x - 15;

演習 16 3 曲線の積分 MEMO

プログラミング技法 演習 4 演習 17 4 微分方程式の解法 演習 実習 4 1 教材プリント 4 節の問題 4 2,4 5 のプログラム, および下のファイルへの書き込みプログラムをもとに, オイラー法, 改良オイラー法, ルンゲ クッタ法を用いて,dx/dt = x の解曲線を計算し, 曲線をグラフ表示せよ. 初期値は適当に幾つかの値で試すこと.( プログラムは適宜変更すること ) また, 同じプログラムを用いて, 以下の方程式の解曲線を計算せよ. dx dt = cos t ( 解軌跡は sin 関数の形状になるはずである ) ファイル書き込みプログラム #include <stdio.h> int main(void) FILE *fp; int i; fp = fopen("testfile.csv","w"); for (i = 0; i < 10; i++) fprintf(fp, "%d,%d\n",i, 10 - i); fclose(fp); return 0; 実習 4 2 回路のシミュレーション右図のような RC 回路についてシミュレーションを行なう. コンデンサには q 0 の電荷 ( 通常は 0) が蓄えられているとし, 時刻 t = 0 でスイッチをオンにしたときの, 回路の動作について計算を行なう. 電流 i の回路方程式は Ri + 1 idt = E C と表わせる. ここで,i = dq/dt を用いて上式を書き替えると, dq dt + q RC = E R となる. この微分方程式より, コンデンサに掛かる電圧 v c を計算 (v c = q/c) することができる. 1. この考え方を用いて,v c の計算をせよ. なお,R = 100[Ω],C = 100[µF],E = 5[V] とし, コンデンサの初期電荷は以下の 2 通りとする. (a)q 0 = 0[C], (b)q 0 = 5[mC] 2. 結果を t v c グラフとして表示せよ.

演習 18 4 微分方程式の解法 実習 4 3 教材プリントの問題 4 3 で用いた連立微分方程式を解くプログラムを用いて, 自由落下のシミュレーションを行う. 1. 自由落下の運動を表わす微分方程式 d y dt = v m d v dt = mg (m はこの場合は任意の値 ) の解軌跡の計算をせよ. また,t v 平面,t y 平面のグラフを表示し, 自由落下の現象がみられるか確認せよ. 2. 落下時に物体に働く空気の抵抗を考慮すると, 方程式は d y dt = v m d v = mg + kv dt となる.k は粘性係数であり, 抵抗が強ければ k の値が大きくなる. 適当な m, k を定めて,1. の場合と比較せよ. 実習 4 4 振り子のシミュレーション初等物理で扱う単振り子は, 振幅が小さい場合など, 制約がある状態で近似的に議論をしている. 計算機を用いた初期値問題では, このような近似をせずに, 振り子の状態を計算することができる. 鉛直方向からの角度 θ に注目し, 微分方程式を組み立てると, m d2 (lθ) dt 2 = mg sin θ θ l ω m のような 2 階の微分方程式となる. ここで, 角度と角速度 ω の関係式 dθ/dt = ω を用いると, 微分方程式は以下のようになる. dθ dt = ω dω dt = g l sin θ 1. 上記の振り子の微分方程式の考え方を用いて, 以下の場合について, シミュレーションを行なえ. t = 0.01 とし,200 ステップ程度計算すること. (a) (θ, ω) = (π/6, 0), l = 1 (b) (θ, ω) = (0, 10), l = 1 2. 結果を t ω および,t θ のグラフとして表示せよ.

プログラミング技法 演習 4 演習 19 実習 4 5 以下の式は, ローレンツ方程式と呼ばれる特殊な解軌跡が表われる微分方程式である. 問題 4 3 で用いた連立微分方程式を解くプログラムを 3 元の連立微分方程式用に拡張し, 下記の微分方程式について, 解曲線を計算せよ. 刻み幅, 初期値などは適当に定めること. dx = σ(y x) dt dy = ρx y xz dt dz = βz + xy, ただしβ = 8/3, σ = 10, ρ = 24 dt 実習 4 6 斜方投射のシミュレーション図のように物体を斜めに投げ上げた場合について考える. このような場合は, 横方向と縦方向が独立した運動になり, それぞれ y v 0 m F F x = ma x = 0 F y = ma y = mg のような運動方程式となる. この式は, 以下のような 4 元の連立微分方程式と表すことができる. v 0y (x 0, y 0 ) v 0x x dx dt = v x, dy dt = v y, dv x dt = 0 dv y dt = g 1. 上記の考え方に基いて, 初期位置 (0,0), 初速度 (1[m/s],1[m/s]) として, 軌跡を計算せよ. 2. プログラムを修正し, 初速度と打ち出し角度を指定して, シミュレーションを行なうようにせよ. 3. 初速度 10[m/s] とし, 角度を 30,45,60 度 ( ラジアンに変換の必要あり ) とし, 到達距離を比較せよ.

演習 20 4 微分方程式の解法 実習 4 7 ( やや難 ) n 次の連立微分方程式をオイラー法を用いて計算するプログラムについて,n の値が大きくなると変数の数が増え, プログラムが冗長になる. これを防止するために, 計算する変数を配列を用いて処理することを考える. 例えば, 以下のような微分方程式 dx 1 dt = x 2 dx 2 dt = x 1 を, 次のような関数として表わすとする. void equ(double x[],double dx[], double t) dx[0] = x[1]; dx[1] = -x[0]; 1. このような配列を用いた形のオイラー法の計算プログラムを作成せよ. 2. 作成したプログラムを用いて, 上記の微分方程式について, 初期値を (x 1, x 2 ) = (1, 0) として解曲線を計算せよ. 3. 作成したプログラムを用いて, 演習 4 5 の方程式の解曲線を計算せよ.

プログラミング技法 演習 4 演習 21 演習 4 解説, プログラム例 実習 4 1 dx/dt = cos t に対しては,sin 曲線が描けるはずである. ただし, t が大きいと, 正しい形にならない場合がある. 01:#include <stdio.h> 02:#include <math.h> 03:double f(double x, double t); 04:int main(void) 05: 06: FILE *fp = fopen("euler.csv","w"); 07: double x = 0, new_x; 08: double t = 0, dt = 0.01, t_end = 2*3.1415; 09: while (t <= t_end) 10: new_x = x + dt * f(x, t); 11: fprintf(fp,"%f, %f\n ", t, x); 12: x = new_x; 13: t = t + dt; 14: 15: fclose(fp); 16: return 0; 17: 18:double f(double x, double t) 19: 20: return cos(t); 21: 実習 4 2 微分方程式を表わす関数は以下のようになります. また, グラフは t q グラフを示しています. 縦軸は v c = q/c の関係から変換することができます. double f(double x, double t) double R = 100, C = 100e-6, E = 5; return E/R - x/(r*c); 0.005 0.004 q-t グラフ q1 q2 0.003 q 0.002 0.001 0 0 0.05 0.1 実習 4 3 1. 関数 f1,f2 を以下のようにすることで自由落下のシミュレーションが行える. t double f1(double x1, double x2, double t) return x2; double f2(double x1, double x2, double t) return -9.8; 初速度 0 からの自由落下の様子のフラフを示す.

演習 22 4 微分方程式の解法 y 0-20 -40-60 -80-100 -120 t-y グラフ -140 0 1 2 3 4 5 t v 0-5 -10-15 -20-25 -30-35 -40-45 t-v グラフ -50 0 1 2 3 4 5 2. 関数 f1,f2 を以下のようにすることで自由落下のシミュレーションが行える. この場合は k = 1.0, m = 1.0 としている. double f1(double x1, double x2, double t) return x2; double f2(double x1, double x2, double t) double k = 1, m = 1; return -9.8 - k / m * x2; 初速度 0 からの落下の様子を示す. 重力と粘性抵抗が釣り合い, 一定速度に漸近することが分かる. t t-y グラフ t-v グラフ 0 0 y -20 v -5 実習 4 4-40 0 1 2 3 4 5 t -10 0 1 2 3 4 5 微分方程式の関数は以下のような 2 元の連立になります. グラフは, 左の場合, 普 通の揺れ方を示していますが, 右の場合, 振り子は回転しており,θ の値は増加しつづけています. t

プログラミング技法 演習 4 演習 23 void f1(double x1, double x2, double t) return x2; void f1(double x1, double x2, double t) double g = 9.8, l = 1; return -g/l * sin(x1); 0.6 18 0.4 16 14 0.2 12 θ 0 θ 10 8-0.2 6-0.4 4 2-0.6 0 0.5 1 1.5 2 2.5 t 0 0 0.5 1 1.5 2 2.5 t 実習 4 5 グラフ表示例 初期値によって, 波形は大きく異なります. なお, 時間刻みを小く取らないと, 計算が上手くいかない場合があります. x t-x グラフ 20 17.5 15 12.5 10 7.5 5 2.5 0-2.5-5 -7.5-10 -12.5-15 0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 5 t y x-yグラフ 30 25 20 15 10 5 0-5 -10-15 -20-15 -10-5 0 5 10 15 20 x 実習 4 6 プログラム例を示します. グラフは一般的な放物線なので, ここでは割愛します.

演習 24 4 微分方程式の解法 1:#include <stdio.h> 2:#include <math.h> 3:double f1(double, double, double, double, double); 4:double f2(double, double, double, double, double); 5:double f3(double, double, double, double, double); 6:double f4(double, double, double, double, double); 7:int main() 8: 9: FILE *fp = fopen("euler-2d.csv","w"); 10: double t = 0, dt = 0.01, t_end = 1; 11: double x1 = 0, x2 = 1, new_x1, new_x2; 12: double x3 = 0, x4 = 1, new_x3, new_x4; 13: while (t <= t_end) 14: fprintf(fp,"%f, %f, %f, %f, %f\n ", t, x1, x2,x3,x4); 15: new_x1 = x1 + dt * f1(x1, x2, x3, x4, t); 16: new_x2 = x2 + dt * f2(x1, x2, x3, x4, t); 17: new_x3 = x3 + dt * f3(x1, x2, x3, x4, t); 18: new_x4 = x4 + dt * f4(x1, x2, x3, x4, t); 19: x1 = new_x1; x2 = new_x2; 20: x3 = new_x3; x4 = new_x4; 21: t = t + dt; 22: 23: fclose(fp); 24: return 0; 25: 26:double f1(double x1, double x2, double x3, double x4, double t) 27: 28: return x2; // dx/dt = vx 29: 30:double f2(double x1, double x2, double x3, double x4, double t) 31: 32: return 0; // dvx/dt = 0 33: 34:double f3(double x1, double x2, double x3, double x4, double t) 35: 36: return x4; // dy/dt = vy 37: 38:double f4(double x1, double x2, double x3, double x4, double t) 39: 40: return -9.8; // dvy/dt = -g 41: 2. 上記のプログラムの x2,x4 の初期値を, それぞれ x2=cos(angle); x4=cos(angle) とすればよい.angle は打ち出し角度 ( ラジアン ) です. 3. 45 度の場合が一番遠くへ到達します.

プログラミング技法 演習 5 演習 25 5 構造体 演習 実習 5 1 1. 左のプログラムを入力実行し, 構造体の動作を確認せよ. 2. 右のプログラムは左と同様の動作を意図して作られたものである. 実行できるか確認せよ. 1:#include <stdio.h> 2: 3:struct sample 4: int a,b; 5: double x; 6:; 7: 8:int main() 9: 10: struct sample A=1,2,5.0; 11: struct sample B,C; 12: printf("a の内容の表示 \n"); 13: printf("%d %d %f\n", A.a,A.b,A.x); 14: B.a = A.a; B.b = A.b; B.x = A.x; 15: printf("a のメンバの 2 倍の値が表示 \n"); 16: printf("%d %d %f\n", 17: A.a+B.a,A.b+B.b,A.x+B.x); 18: C = A; 19: printf("a と同じ内容が表示 \n"); 20: printf("%d %d %f\n", C.a,C.b,C.x); 21: return 0; 22: 1:#include <stdio.h> 2: 3:struct sample 4: int a,b; 5: double x; 6:; 7: 8:int main() 9: 10: struct sample A=1,2,5.0; 11: struct sample B,C; 12: printf("a の内容の表示 \n"); 13: printf("%d %d %f\n", A); 14: B=1,2,5.0; 15: printf("a のメンバの 2 倍の値が表示 \n"); 16: printf("%d %d %f\n",a+b); 17: C = A; 18: printf("a と同じ内容が表示 \n"); 19: printf("%d %d %f\n", C); 20: return 0; 21: 実習 5 2 以下のプログラムは, 構造体の基本的な代入などの文法を確認するためのものである. 1. プログラムを実行し, 値の代入の文法の確認をせよ. 特に a のように配列のメンバに関連する文法に注意すること. 2. 15 行目のコメントをはずし,B にどのような値が代入されたか確認せよ. 3. 18 行目で, 構造体の配列 C の 0 番目に A を代入している.19 行目以降に,C[0] のメンバの表示するためのプログラムを追加せよ. 1:#include <stdio.h> 2: 3:struct example1 4: int a[3]; 5: double b; 6: char c; 7:; 8:int main() 9: 10: struct example1 A = 1,2,3,2.0,'a', B, C[10]; 11: printf ("%d %d %d\n", A.a[0], A.a[1], A.a[2]); 12: printf ("%f %c\n", A.b, A.c); 13: B.a[0] = 10; B.a[1] = 15; B.a[2] = 20; 14: B.b = 0.1; B.c = 'Z'; 15: //B=A; 16: printf ("%d %d %d\n", B.a[0], B.a[1], B.a[2]); 17: printf ("%f %c\n", B.b, B.c); 18: C[0] = A; 19: // (*) 20: return 0; 21:

演習 26 5 構造体 実習 5 3 以下は,5 人分のデータを exam 構造体の配列に読み込み, その中で最高点の人のデータを表示するプログラムである. 空白部を埋めよ. 1:#include <stdio.h> 2:#define N 5 3:struct exam // 構造体定義 4: int no, math, eng, phys; 5:; 6:int total(struct exam); // 合計を求める関数 7:int main() 8: 9: int i; 10: struct exam data[n], MAX; 11: for (i = 0; i < N; i++) 12: printf(" 番号数学英語物理 \n"); 13: scanf("%d %d %d %d", // 入力 14: 15: ); 16: 17: MAX = data[0]; 18: for (i = 1; i < N; i++) // 最高値判定 19: if ( ) 20: MAX = data[i]; 21: 22: printf(" 最高点の人は %d 番の人です. 合計は %d です.\n" 23: ); 24: return 0; 25: 26: 27:int total(struct exam data) 28: 29: 実習 5 4 BMI とは 身長からみた体重の割合を示す体格指数であり, 身長, 体重から BMI = ( 体重 [kg])/( 身長 [cm]) 2 で与えられる. 以下のプログラムは身長, 体重の値より BMI 値を計算するものである. プログラムを以下に示した構造体 bmi を用いるように書換えよ. BMI 計算プログラム 構造体 bmi 1:#include <stdio.h> 2:#include <math.h> 3:#define N 2 4: 5:int main() 6: 7: double height[n]; // 身長 8: double weight[n]; // 体重 9: double BMI[N]; //BMI 値 10: int i; 11: for (i = 0; i < N; i++) 12: printf(" 身長 [cm] 体重 [kg]\n"); 13: scanf("%lf %lf", &height[i], &weight[i]); 14: BMI[i] = weight[i] / pow(height[i],2); 15: 16: printf(" 身長体重 BMI 値 \n"); 17: for (i = 0; i < N; i++) 18: printf("%f %f %f\n",height[i], weight[i], 19: BMI[i]); 20: 21: return 0; 22: struct bmi double w; // 身長 double h; // 体重 double bmi; // BMI ;

プログラミング技法 演習 5 演習 27 実習 5 5 商品の売上の統計を出したい. 具体的には, 商品の型番, 売上個数を入力すると, 売上のパーセンテージを計算し,( 型番, 個数, 率 ) を表示するようなプログラムを作成する. このとき, プログラムは上記のように型番, 個数, 率をメンバを持った構造体 data を用いる. 1. 以下のプログラムの空欄をコメントを参考に埋めよ. また, プログラムを実行し, 適当なデータを入力し動作を確認せよ. 2. 総和を求める部分と, 各パーセンテージを求める部分を関数にしたい. それぞれ, int sum(struct data d[]); double percent(struct data d, int total); のような形の関数を作成せよ. さらにそれらの関数を用いる形で, プログラム全体を構成しなおせ. また,1 の問題と同様に, 実行し適当なデータを入力し動作を確認せよ. #include <stdio.h> #define N 5 // データの数 // 構造体の定義 int main() int i, total = 0; struct data dat[n]; for (i = 0; i < N; i++) // データの読み込み ; for (i = 0; i < N; i++) // 総和の計算 for (i = 0; i < N; i++) // 各パーセンテージの計算 for (i = 0; i < N; i++) // 表示 return 0;

演習 28 5 構造体 実習 5 6 示したプログラムは構造体を用いて, 数学のベクトルを表わしたものである. 1. 入力して実行せよ. 2. ベクトルの実数倍の計算をする関数, ベクトルの長さを計算する関数と, 内積を計算する関数を作成せよ. 関数は以下のような形にすること. struct vector mul(double a, struct vector v); double inner(struct vector v1, struct vector v2); double length(struct vector v); なお, 内積の計算は以下の式で求められる. a b = a x b x + a y b y 3. 下図のように 2 本のベクトルからなる三角形の面積を求める関数を作成せよ. 型は double triangle(struct vector A, struct vector B); とする. また, 作成した関数を用いるような, 適当な main 関数を作成し実行せよ. なお, 三角形の面積は S = a 2 b 2 (a b) 2 2 で求めることができる. 1:#include <stdio.h> 2:#include <math.h> 3:struct vector 4: double x,y; 5:; 6:struct vector add(struct vector v1, struct vector v2); 7:int main() 8: 9: struct vector v1, v2, v3; 10: printf(" ベクトル 1(x y)="); 11: scanf("%lf %lf",&v1.x, &v1.y); 12: printf(" ベクトル 2(x y)="); 13: scanf("%lf %lf",&v2.x, &v2.y); 14: v3 = add(v1,v2); 15: printf("a+b=(%f, %f)", v3.x, v3.y); 16: return 0; 17: 18:struct vector add(struct vector v1, struct vector v2) 19: 20: struct vector v; 21: v.x = v1.x + v2.x; 22: v.y = v1.y + v2.y; 23: return v; 24: ベクトルから構成される三角形

プログラミング技法 演習 5 演習 29 演習 5 プログラム例 実習 5 3 プログラム例です. 1:#include <stdio.h> 2:#define N 5 3:struct exam // 構造体定義 4: int no, math, eng, phys; 5:; 6:int total(struct exam); // 合計を求める関数 7:int main() 8: 9: int i; 10: struct exam data[n], MAX; 11: for (i = 0; i < N; i++) 12: printf(" 番号数学英語物理 \n"); 13: scanf("%d %d %d %d", // 入力 14: &data[i].no, &data[i].math, 15: &data[i].eng, &data[i].phys); 16: 17: MAX = data[0]; 18: for (i = 1; i < N; i++) // 最高値判定 19: if (total(max) < total(data[i])) 20: MAX = data[i]; 21: 22: printf(" 最高点の人は %d 番の人です. 合計は %d です.\n" 23:,MAX.no, total(max)); 24: return 0; 25: 26: 27:int total(struct exam data) 28: return data.math + data.eng + data.phys; 29: 実習 5 4 プログラム例です. 1:#include <stdio.h> 2:#define N 2 3:struct bmi 4: double w; // 身長 5: double h; // 体重 6: double bmi; // BMI 7:; 8: 9:int main() 10: 11: struct bmi dat[n]; 12: int i; 13: for (i = 0; i < N; i++) 14: printf(" 身長体重 \n"); 15: scanf("%lf %lf",&dat[i].h, &dat[i].w); 16: dat[i].bmi = dat[i].h / (dat[i].w * dat[i].w); 17: 18: printf(" 身長体重 BMI 値 \n"); 19: for (i = 0; i < N; i++) 20: printf("%f %f %f\n",dat[i].h, dat[i].w, 21: dat[i].bmi); 22: 23: return 0; 24: 実習 5 5 2 の関数実装をした例を示します. 1:#include <stdio.h> 2:#define N 10 3: 4:struct data 5: int no; 6: int score; 7: double per; 8:; 9:int sum(struct data d[]); 10:double percent(struct data d, int total); 11: 12:int main() 13: 14: int i, total = 0; 15: struct data dat[n]; 16: for (i = 0; i < N; i++) // データの読み込み 17: scanf("%d %d", &dat[i].no, &dat[i].score); 18: ; 19: for (i = 0; i < N; i++) // 総和の計算 20: total += dat[i].score; 21: 22: for (i = 0; i < N; i++) // 各パーセンテージの計算 23: dat[i].per = (double)dat[i].score / total * 100; 24: 25: for (i = 0; i < N; i++) // 表示 26: printf("%3d %5d %6.3f\n", 27: dat[i].no, dat[i].score, dat[i].per); 28: 29: return 0; 30: 31:int sum(struct data d[]) 32: 33: int total = 0, i; 34: for (i = 0; i < N; i++) 35: total += d[i].score; 36: 37: return total; 38: 39:double percent(struct data d, int total) 40: 41: return (double)d.score / total * 100; 42:

演習 30 5 構造体 実習 5 6 2. 関数のみ示します. struct vector mul(double a, struct vector v) struct vector tmp; tmp.x = a * v.x; tmp.y = a * v.y; return tmp; double inner(struct vector v1, struct vector v2) return v1.x * v2.x + v1.y * v2.y; double len(struct vector v) return sqrt(v.x*v.x + v.y*v.y); 3. プログラム全体を示します.2. で作成した関数を利用していることに注目してください. #include <stdio.h> #include <math.h> struct vector double x,y; ; struct vector add(struct vector v1, struct vector v2); double inner(struct vector v1, struct vector v2); double len(struct vector v); double triangle(struct vector a, struct vector b); int main() struct vector v1, v2; double s; printf(" ベクトル 1(x y)="); scanf("%lf %lf",&v1.x, &v1.y); printf(" ベクトル 2(x y)="); scanf("%lf %lf",&v2.x, &v2.y); s = triangle(v1,v2); printf(" 三角形の面積は %f\n です.\n", s); return 0; struct vector add(struct vector v1, struct vector v2) struct vector v; v.x = v1.x + v2.x; v.y = v1.y + v2.y; return v; double inner(struct vector v1, struct vector v2) return v1.x * v2.x + v1.y * v2.y; double len(struct vector v) return sqrt(v.x*v.x + v.y*v.y); double triangle(struct vector a, struct vector b) return sqrt(pow(len(a),2)*pow(len(b),2) - pow(inner(a, b),2)) / 2.0;

プログラミング技法 演習 6 演習 31 6 スタック, キュー 演習 実習 6 1 せよ. 授業用プリント 45 ページ問題 6 2, 49 ページ問題 6 3 のプログラムを入力し, 実行 実習 6 2 授業用プリントの問題 6 2, 問題 6 3 のプログラムを入力を変更し, スタック, キューの配列の状態を表示する関数 print_stack ( 問題 6 2), および print_queue( 問題 6 3) を作成し, 以下の実行例のように動作するようにせよ. また, このとき, スタックの頂上や, キューの先頭, 末尾の位置が分るように表示を工夫せよ. stack_print 使用例 保存データ入力 (dat1=-1 でデータ取り出し ):1 1.0 (1, 1.000000) *(0, 0.000000) (0, 0.000000) (0, 0.000000)... queue_print 使用例 保存データ入力 (dat1=-1 でデータ取り出し ):1 1.0 H (1, 1.000000) T(0, 0.000000) (0, 0.000000) (0, 0.000000)... 実習 6 3 授業用プリントの問題 6 3 について, 授業で提示したプログラムでは,put を繰り返しキューが一杯になったときに, エラーをチェックするための仕組みが欠けている. エラーチェックをするように関数を修正せよ. ヒント : top と tail の位置で判断するとやりやすい. また無理に配列 queue の要素全てを用いる必要はない.

演習 32 6 スタック, キュー 実習 6 4 以下のプログラムは, プリンタを管理しているコンピュータに送られてくるリクエストを処理する様子を模擬している. 送られてくる信号は, 端末番号とデータ ( この場合は単なる整数 ) である. また,0 番目の端末番号はプリンタを表しており, この信号は, プリンタが印刷可能であることを示している. 1. 7 行目の構造体を扱うキューの関数 put と get を実装せよ. 2. 適当なリクエストデータを入力し, プログラムの動作を確認せよ. 1:#include <stdio.h> 2:#define N 20 3: 4:struct print_data 5: int no; 6: int data; 7:; 8:int head=0, tail=0; 9:print_data queue[n]; 10:void put(print_data dat); 11:print_data get(); 12: 13:int main() 14: 15: int machine_no; 16: print_data pd; 17: while (1) 18: scanf("%d", &machine_no); 19: if (machine_no!= 0) // 端末からの受信 20: pd.no = machine_no; 21: scanf("%d", &pd.data); 22: put(pd); 23: else // プリント可能の信号 24: pd = get(); 25: printf(" 端末 %d のデータ印刷 \n",pd.no); 26: printf("%d\n", pd.data); 27: 28: 29: リクエストデータの例 1 10 3 5 2 95 0 8 10 0 0 実習 6 5 以下のプログラムは入力された数式の括弧が, 正しく対応しているかを確認するためのプログラムである.put 関数と get 関数を追加し, プログラムを実行せよ. なお, このプログラムでは, データが 1 つしかないため, スタックは構造体ではなく,char 型の配列で表されていることに注意すること. URL: http://www.ee.toyota-ct.ac.jp/~ohno/programing/ 以下にプログラム ( 一部 ) が示してある. コピーして用いること

プログラミング技法 演習 6 演習 33 実習 6 6 以下のプログラムは, 授業用プリント 42 ページで示した, 逆ポーラント表記による電卓プログラム ( 整数の加減算のみ ) である.int 型のスタック関数 put と get を追加し, プログラムを実行せよ. 入力例としては, 以下のようなものが考えられる. 10 20 + = 10 + 20 10 20 30 - + = (20 30) + 10 括弧対応チェックプログラム 01:#include <stdio.h> 02:#include <ctype.h> 03:#define N 20 04:int top=0; 05:char stack[n]; 06:void push(char dat); /*char 型のスタック */ 07:char pop(); 08: 09:int main() 10: 11: char dat; 12: while ((dat = getchar())!= EOF) 13: switch (dat) 14: case '(' : case '[': case '': /* 括弧開く */ 15: push(dat); 16: break; 17: case ')': /* 以下閉括弧の判定 */ 18: if (pop()!= '(') 19: printf(" 括弧非対応です \n"); 20: 21: break; 22: case '': 23: if (pop()!= '') 24: printf(" 括弧非対応です \n"); 25: 26: break; 27: case ']': 28: if (pop()!= '[') 29: printf(" 括弧非対応です \n"); 30: 31: break; 32: 33: 34: 逆ポーランド電卓プログラム 01:#include <stdio.h> 02:#include <ctype.h> 03:#define N 20 04:int top=0; 05:int stack[n]; 06:void push(int dat); /* int 型のスタック関数 */ 07:int pop(); 08: 09:int main() 10: 11: int input; 12: int a, b; 13: int data; 14: while (1) 15: input = (char) fgetc(stdin); 16: if (isdigit(input)) /* 数字の処理 */ 17: ungetc(input, stdin); 18: scanf("%d",&data); 19: push(data); 20: else if (isspace(input)) /* 空白, 改行の処理 */ 21: else if (ispunct(input)) /* 演算子の処理 */ 22: switch (input) 23: case '+' : /* 加算 */ 24: a = pop(); 25: b = pop(); 26: push(a+b); 27: break; 28: case '-' : /* 減算 */ 29: a = pop(); 30: b = pop(); 31: push(a+b); 32: break; 33: case '=' : /* 計算結果表示 */ 34: printf("%d\n", pop()); 35: break; 36: default : 37: printf("???\n"); 38: 39: 40: 41: return 0; 42: Note: isdigit や isspace などの, 特殊な関数を用いています. 感心のある人は, 調べてみるといいでしょう.

演習 34 6 スタック, キュー 演習 6 プログラム例 実習 6 2 例示したプログラムでは, スタック, キューそれぞれ print_** という関数を作成し, データ操作ごとに, その関数を呼び出す構成にしています. #include <stdio.h> #define N 10 struct Data int dat1; double dat2; ; int top=0; struct Data stack[n]; void print_stack() int i; for (i = 0; i < N; i++) if (i == top) printf("*"); else printf(" "); printf("(%d, %f)\n", stack[i].dat1, stack[i].dat2); void push(struct Data d) /* データの保存関数 */ if (top < N) stack[top] = d; top++; print_stack(); struct Data pop() /* データの取り出し関数 */ struct Data ret=0,0.0; if (top > 0) top--; ret = stack[top]; print_stack(); return ret; int main() struct Data D; while (1) printf(" 保存データ入力 \n"); printf("(dat1=-1 でデータ取り出し ):"); scanf("%d %lf", &D.dat1, &D.dat2); if (D.dat1 == -1) D = pop(); printf(" 取り出したデータ :(%d %f)\n",d.dat1, D.dat2); else push(d); return 0; #include <stdio.h> #define N 10 struct Data int dat1; double dat2; ; int head=0, tail=0; struct Data queue[n]; void print_queue() int i; for (i = 0; i < N; i++) if (i == head) printf("h"); else printf(" "); if (i == tail) printf("t"); else printf(" "); printf("(%d, %f)\n", queue[i].dat1, queue[i].dat2); void put(struct Data d) /* データの保存関数 */ queue[tail] = d; tail++; if (tail >= N) tail = 0; print_queue(); struct Data get() /* データの取り出し関数 */ struct Data ret = 0,0.0; if (head!= tail) ret = queue[head]; head++; if (head >= N) head = 0; print_queue(); return ret; int main() struct Data D; while (1) printf(" 保存データ入力 \n"); printf("(dat1=-1 でデータ取り出し ):"); scanf("%d %lf", &D.dat1, &D.dat2); if (D.dat1 == -1) D = get(); printf(" 取り出したデータ :(%d %f)\n",d.dat1, D.dat2); else put(d); return 0;

プログラミング技法 演習 6 演習 35 実習 6 3 以下の図のように,head+1 = tail のとき, キューが一杯であると判断します. しかし,tail = 0,head = N-1 の場合を考慮する必要があるので, プログラムに示すように, ここでは count_up という関数を用意し, チェックを行なっています. head これ以上 headが増えると head=tailとなってキューが空の状態と同じになってしまう tail 0 1 2 3 4 5 6 head+1 = tail のとき, キューが一杯であるとして, チェックを行う int count_up(int c) c++; if (c >= N) c = 0; return c; void put(struct Data d) // データの保存関数 if (count_up(tail) == head) puts ("queue is full."); else queue[tail] = d; tail = count_up(tail); struct Data get() // データの取り出し関数 struct Data ret = 0,0.0; if (head!= tail) ret = queue[head]; head = count_up(head); return ret; 実習 6 5 問題文に記したように, データの数が 1 つなので, スタックの関数は以下のようた形になります. 基本的なプログラムの手順は同じであることに注目してください. void push(char dat) if (top < N) stack[top] = dat; top++; char pop() if (top > 0) top--; return stack[top]; else return 0;

演習 36 6 スタック, キュー MEMO

プログラミング技法 演習 7 演習 37 7 連結リスト 演習 実習 7 1,7 3 は URL: http://www.ee.toyota-ct.ac.jp/~ohno/programing/ 以下にプログラム ( 一部 ) が示してある. コピーして用いること 実習 7 1 下記のプログラム 1 は連結リストの各関数の動作を確認するためのものである. 空欄を埋め, 実行せよ. なお, 未使用のセルは data が-1 の場合とする. #include <stdio.h> #define MAX 100 struct CELL int data; int next; ; int get_empty_cell(); void initialize(); void add_data(int no1, int data); void del_data(int no1); void print_data(); struct CELL list[max]; int main() int no, i; initialize(); /* リストの初期化 */ printf(" 繰り返し回数 : "); scanf("%d", &no); for (i = 0; i < no; i++) add_data(0, i); print_data(); for (i = 0; i < no; i++) del_data(0); print_data(); return 0; int get_empty_cell() int i,ret = -1; for (i = 1; i < MAX; i++) if (list[i].data == -1) ret = i; break; return ret; void initialize() void add_data(int no, int data) void del_data(int no) void print_data() int no = 0; while(list[no].next!= -1) no = list[no].next; printf("%d ", list[no].data); printf("\n"); 実習 7 2 実習 7 1 のプログラムは連結リストの先頭にデータが追加されていく. プログラム 1 を変更し, 新しいデータがリストの最後に追加されるようにせよ.

演習 38 7 連結リスト 実習 7 3 連結リストの中の n 番目のセルの配列番号を返す関数 position を実装せよ. 作成した関数を利用して, 下記のプログラム 2 を実行せよ. #include <stdio.h> #include <ctype.h> #define MAX 100 struct CELL char data; int next; ; int get_empty_cell(); void initialize(); void add_data(int no1, char data); void del_data(int no1); void print_data(); int list_len(); int position(int no); struct CELL list[max]; int main() int menu, no, p; char c = 0; initialize(); while (1) printf("1: 入力 2: 削除 3: 出力 4: 終了 "); scanf("%d", &menu); switch (menu) case 1: // 入力 printf(" 挿入位置 :"); scanf("%d", &no); if (no > list_len()) puts(" 範囲外です "); break; p = position(no); printf(" データ :"); while(!isprint(c=getchar())); /*1 文字入力 */ add_data(p, c); break; case 2: printf(" 削除位置 :"); scanf("%d", &no); if (no >= list_len()) printf(" 範囲外です \n"); break; p = position(no); del_data(p); break; case 3: print_data(); break; if (menu == 4) break; return 0; 以下関数群が続きます web 上のプログラムには提示されています

プログラミング技法 演習 7 演習 39 実習 7 4 示したプログラムは数値データが羅列されたデータファイル (numbers.dat) から, データを読み取り, その和を計算するプログラムである. 読み取ったデータはリストに保存さる. また, 和を計算する関数は再帰呼び出しによって行なっている. 適当なデータファイルを作成し, プログラムの動作を確認せよ. Note: 前半部データの読み取りは, ファイルの終了 (EOF) が来るまで, 読み込み続けるように作られています. データの数がはっきりしなくても, 読み込むために良く用いられる手法です.ungetc 関数などは有用な関数なので, 感心があれば調べると良いでしょう. #include <stdio.h> #define MAX 100 struct CELL double data; int next; ; struct CELL list[max]; int get_empty_cell(); void initialize(); void add_data(int no1, double data); double sum(int no); int main() FILE *fp; double dat; char c; fp = fopen("numbers.dat","r"); initialize(); /* ファイルのデータが無くなるまで読み込み */ while ((c = getc(fp))!= EOF) ungetc(c,fp); fscanf(fp,"%lf\n", &dat); add_data(0, dat); printf("%f\n", sum(0)); fclose(fp); return 0; int get_empty_cell() 略 void initialize() 略 void add_data(int no, double data) 略 double sum(int no) /* リストのデータの和を計算 */ double s = 0; if (list[no].next!= -1) no = list[no].next; s = list[no].data; s += sum(no); return s; 実習 7 5 ( やや難 ) 以下の図のように点がデータファイルに入力されている. この点の集りによって, 一本の曲線を表わしているものとする. この点の始点から終点の長さを求めるプログラムを作成せよ.

演習 40 7 連結リスト ソフトウェア技術 B 7 演習 解説 実習 7 2 メイン関数の一部を変更しています.while 文を用いて, 連結リストの最後尾を調べていますが, 他にもキューの考え方を応用し, 最後尾を別の変数に保存するなどの方法も考えられます. printf(" 繰り返し回数 : "); scanf("%d", &no); for (i = 0; i < no; i++) p = 0; while(list[p].next!= -1) p = list[p].next; add_data(p, i); print_data(); 実習 7 3 関数 position のみを示します. int position(int no) int p = 0, i; for (i = 0; i < no; i++) if (list[p].next!= -1) p = list[p].next; return p; 実習 7 5 セルのデータは x,y と 2 つのデータを持たせる形になっています. また, セルが未使用かどうかをメンバ use を用いて判断します. 曲線の距離は line_len において求めることができます. #include <stdio.h> #include <math.h> #define MAX 100 struct CELL double x,y; int use; // セルの使用状況 int next; ; int get_empty_cell(); void initialize(); void add_data(int no1, double x, double y); void del_data(int no1); double line_len(int no); struct CELL list[max]; int main() FILE *fp; double x, y; char c; fp = fopen("line.dat","r"); initialize(); while ((c = getc(fp))!= EOF) ungetc(c,fp); fscanf(fp,"%lf %lf", &x, &y); add_data(0, x, y); printf("%f\n", line_len(0)); fclose(fp); return 0; int get_empty_cell() int i,ret = -1; for (i = 1; i < MAX; i++) if (list[i].use == 0) ret = i; break; return ret; void initialize() int i; list[0].next = -1; for (i = 0; i < MAX; i++) list[i].use = 0; // use が 0 ならばセルは未使用 list[i].x = list[i].y = 0; void add_data(int no, double x, double y) int no2 = get_empty_cell(); if (no2 == -1) printf("buffer overflow\n"); return; list[no2].x = x; list[no2].y = y; list[no2].use = 1; list[no2].next = list[no].next; list[no].next = no2; void del_data(int no) int no2 = list[no].next; list[no].next = list[no2].next; list[no2].use = 0; double line_len(int no) double s; if (list[no].next!= -1) no = list[no].next; if (list[no].next!= -1) s = line_len(no); s += sqrt(pow(list[no].x - list[list[no].next].x,2) + pow(list[no].y - list[list[no].next].y,2)); return s;

プログラミング技法 演習 7 演習 41 MEMO