Ex13Ans

From Prog0

Jump to: navigation, search

演習第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;
}
Personal tools