Ex13Ans
From Prog0
演習第13回
Contents |
解答例
A問題
#include <stdio.h> #include <stdlib.h> #define QSIZE 100 void enqueue(int); int dequeue(void); int isFull(void); /* プロトタイプ宣言も必要 */ int isEmpty(void); int queue[QSIZE]; int head = 0; int tail = 0; int main(){ int data, status, i; while (1) { printf("input>> "); status = scanf("%d", &data); if (status != 1) break; /* 入力値が0の場合はデータ取り出し、それ以外ならデータを キューに追加する */ if (data == 0) printf("Data: %d\n", dequeue() ); else enqueue(data); printf(" [Queue] "); /* 処理後にキューの内容を表示してみる */ for ( i=head; i!=tail; i=(i+1)%QSIZE ) printf("%d ", queue[i]); printf("\n"); } return 0; } void enqueue(int num){ if (isFull() == 1) { /* isFull() のみでもよい */ /* キューがいっぱいの場合のエラー処理 */ printf("Queue overflow!\n"); exit (2); } queue[tail] = num; tail = (tail+1)%QSIZE; } int dequeue(void){ int val; if (isEmpty() == 1) { /* isEmpty() のみでもよい */ /* キューが空の場合のエラー処理 */ printf("Queue is empty!\n"); exit (3); } val = queue[head]; head = (head+1)%QSIZE; return val; } /* isFull関数:キューがいっぱいなら1を返し、そうでなければ0を返す */ int isFull(void){ if ( (tail+1)%QSIZE == head ) return 1; else return 0; /* if-else文を使わず「return ((tail+1)%QSIZE == head);」とするのでもOK */ } /* isEmpty関数:キューが空なら1を返し、そうでなければ0を返す */ int isEmpty(void){ if ( head == tail ) return 1; else return 0; /* if-else文を使わず「return (head == tail);」とするのでもOK */ }
A-2 情報落ちの実験
ファイル名: ex13a2.c
- 元のプログラムでは、項数がだいたい1億以上になると、項を増やしても結果が変わらなくなるようです。(Solarisで実験してみたところ 1.64493405783019 より大きくなりませんでした)
- 下のプログラムのように、値が小さい最後の項から n=1 に向かって足し算していくと、情報落ちが起きにくくなります。(実験してみると1億項以上でも少しずつ値が増え続け、最大 1.64493406638257 になりました)
解答プログラム例
#include <stdio.h> int main(){ double x, s1, s2; int n, nmax; printf("何項計算しますか?: "); scanf("%d", &nmax); /* 注:int型使用のため2147483646が限界 */ /* nmaxから逆順に加算 */ s2 = 0.0; for( n=nmax; n>=1; n-- ){ x = (double)n; s2 += 1.0/(x*x); } printf("1/n^2の総和: %.14f\n", s2); return 0; }
B問題
/*************************************** * スタック(検索機能追加)(lec13-1b.c をもとに改変) * 2024-6 ***************************************/ #include <stdio.h> #include <stdlib.h> #define STSIZE 100 void push(int); int pop(void); void detect(void); int stack[STSIZE]; int top = 0; int main(){ int data, status, i, n; while (1) { printf("\n--- Input [+] to push, [-] to pop, [0] to detect --- >> "); status = scanf("%d", &data); if (status != 1) break; // Control + d で抜ける /* 入力値が正の場合はそのデータをpush, 負の場合はpop, 0の場合はさらに値の入力を促し、スタック中を検索 */ if (data > 0) push(data); if (data < 0) printf("Data: %d\n", pop() ); if (data == 0) detect(); /* 処理後にスタックの内容を表示 */ printf(" [Stack] "); for ( i=0; i<top; i++ ) printf("%d ", stack[i]); printf("\n"); } return 0; } /* 関数群 */ void push(int num){ if (top == STSIZE) { /* スタックがいっぱいの場合、エラー処理を行う */ printf("Stack overflow!\n"); exit (2); } stack[top] = num; top++; } int pop(void){ /* スタックが空の場合、エラー処理を行う */ if (top == 0) { printf("Stack is empty!\n"); exit (3); } top--; return stack[top]; } void detect(void) { int i, num; /* スタックが空の場合、エラー処理を行う */ if (top == 0) { printf("Stack is empty!\n"); exit (3); } /* 検索すべき数字を入力させる */ printf("Detect what ? :"); scanf("%d", &num); /* 検索 */ for(i = 0; i<top; i++){ if(stack[i] == num){ printf("%d exists at stack[%d] \n", num, i); break; } } /* スタック中に検索値が存在しない場合、エラー処理を行う */ if(i == top) { printf("%d not in stack! \n", num); exit (4); } }
B-2 数値計算の誤差について
ファイル名: ex13b2.c
#include <stdio.h> #include <math.h> double x1 = -2691367.32673266; double x2 = -3.6787955329121653e-9; double solve_qudratic(double a, double b, double c, int sel) { double res; if (sel == 1) { res = -b + sqrt(b*b - 4.0*a*c); } else { res = -b - sqrt(b*b - 4.0*a*c); } return res/(2.0*a); } int main() { double a = 1.01; double b = 2718281.0; double c = 0.01; double y1, y2; y1 = solve_qudratic(a, b, c, 0); y2 = solve_qudratic(a, b, c, 1); printf("%e %e\n", fabs((y1-x1)/x1), fabs((y2-x2)/x2)); return 0; }
実行結果:
3.460407e-15 2.612459e-03
Extra問題
E-1 空気抵抗を考慮した落下運動
ファイル名: ex13e1.c
#include <stdio.h> #define G 9.80 /* 重力加速度 */ #define VISC 1.8e-5 /* 空気の粘性係数 */ int main (){ double v, x, t=0.0, tmax, a, m, c_m; double dt=0.00001; /* タイムステップの値(十分小さくとること) */ double dtp, tp=0.0; /* 出力タイミング調整用 */ double pi = 3.14159265358979; /* 円周率 */ printf("初期状態の速度、位置と、計算する時間を入力してください\n"); scanf( "%lg%lg%lg", &v, &x, &tmax ); printf("物体の半径と質量を入力してください\n"); scanf( "%lg%lg", &a, &m ); /* Stokesの抵抗法則:F = 6 * pi * a * viscosity * v c_m * v = 粘性による加速度 となるように c_m を定める */ c_m = 6 * pi * a * VISC / m; printf("出力の間隔を入力してください: "); scanf("%lg", &dtp); if (dtp < dt) dtp = dt; /* おかしな入力は修正 */ /* 最初の出力 */ printf( " 時間 位置 速度 \n" ); printf( "%8.4f %8.4f %8.4f\n", t, x, v ); /* 粘性抵抗がある場合の落下の計算 */ while (t < tmax-dt/10.0){ /* tmax秒になったら終了(少し余裕を持たせる) */ t += dt; x += v * dt; /* 位置を更新 */ v += (-G -c_m*v) * dt; /* 速度を更新 */ tp += dt; /* 一つ前の出力からの時間をカウント */ if (tp > dtp-dt/10.0) { /* 指定した時間が経過したら結果を出力 */ printf( "%8.4f %8.4f %8.4f\n", t, x, v ); tp = 0.0; /* 出力用時間カウンタをリセット */ } } return 0; }