[ quoted from ] 情報演習 課題C-B-1(※)一部抜粋・改変

以下のプログラムは、正の実数xを入力とし、関数f(x)=log(x)について、dを十分小さくしたとき、(f(x+d)-f(x-d))/2dが(1-log(x))/x^2に収束することを、実際に計算して確かめるためのプログラムである。プログラム中do〜whileループで、(f(x+d)-f(x-d))/2dの値が収束するまで、dの値を小さくする。

しかし、以下のプログラムにはいくつか間違いがある。そのため、コンパイルが成功しない、またコンパイルが成功するように修正してもうまく計算を行うことができない。これらの間違いを訂正し、正しいプログラムに修正せよ。


#include <stdio.h>
#include <math.h>

double calculate(double x);  
double f(double x);
double df(double x);
  
int main(void)
{
   double x; 
   
   printf("Input x (> 0.0): ");
   scanf("%lf", x);
   
   if ( x > 0.0) {
     calculate(x); 
   } else {
     printf("x must be greather than 0.\n");
   }
}
        
double calculate(double x)
{
  double d; // delta
  double a, b;

  d = d/2.0;
  a = (f(x+d)-f(x-d))/2.0*d;
  do {
    d = d/2.0; 
    b = a; 
    a = (f(x+d)-f(x-d))/2.0*d;
    printf("d=%lf, (f(x+d)-f(x-d))/2d=%lf\n", d, a);
  } while (fabs(b-a)!=0.0);

  printf("\n[Result]\n");
  printf("(f(x+d)-f(x-d))/2d converged to %lf\n", a);
  printf("df(x)= %lf\n", df(x));
}

double f(double x) { return (log(x) / x); }

double df(double x) { return ((1.0 - log(x)) / (x*x)); }

課題に取り組む前に注意すべきことがあります。このプログラムでは、数学ライブラリ<math.h>を使っているので、そのままではコンパイルできません。コンパイル時に必ず-lmオプションをつけてコンパイルしましょう。

入出力
入力
gcc -lm cb1.c
出力
<その他のエラー文がずらずらと>

デバッグが重要だというのは、課題C-A-1の解説でも述べました。課題C-B-1はずばりそのデバッグの課題です。直すべき箇所の大まかな数を書いておくので、参考にしてください。

カウント基準が曖昧なので、あくまで参考にとどめ、最終的には実際のプログラムの出力結果で正誤判定を行ってください。

このプログラムには、約6種類9個の間違いと、どーでもいい綴りミスが1か所があります。main関数には2種類+α、calculate関数には4種類の間違いがあります。しかし、それら6種類の間違いのうち4種類の間違いは非常に単純なものなので、課題C-A-1の解説を読むなりして注意深く観察すれば簡単に分かるはずです。

重要なのは、calculate関数の部分にある残り2つの間違いです。1つは特に深刻なので明記しておきますが、while (fabs(b-a)!=0.0);の部分です。修正できていなければ確実に再提出です。この部分のコードが誤りであるのは、情報演習のページで見れるCプログラミング資料(PDF)を読めば分かります。(ずばり書いてあるはずです。)

一方もう1つの間違いは非常に気付き難い間違いです。と言うのは、間違い発見と思って直しても、それが依然間違ったままになってしまう可能性が高いからです。こちらは関数の定義域に関係する問題です。このヒントがあれば恐らく分かるでしょう。