C言語関係掲示板

過去ログ

No.488.#defineマクロで値が変わる?

[戻る] [ホームページ]
No.3587

#defineマクロで値が変わる?
投稿者---rolo(2002/11/26 22:14:50)


はじめまして。roloと申します。少しリストが長くなることをお許し下さい。
以下のトラブル(?)に関し、お分かりなる方がいらっしゃいましたら是非ご指導をお願いします。
プログラム自体の処理はルンゲ・クッタ法を用いて微分方程式を解くというものでサンプル1,2に
共通です。
サンプル1では計算過程で使う式を関数の形で定義します。
サンプル2では計算過程で使う式を#defineマクロの形で定義します。
わたしの理解ではこの2つのプログラムは同一だと思うのですが、出力結果にずれが生じます。
f1(他の#defineマクロで定義されている文字を使わない式)をどちらにしても差は出ないのですが
f2(他の#defineマクロで定義されている文字を使う式)を動かすと計算結果に差が出ます。
なお、コンパイラはbcc5.5です。よろしくおねがいします。m(..)m

/*サンプル1*/
#include<stdio.h>
#include<math.h>

double f1(double x1, double x2);	/*--f1,f2を関数で定義--*/
double f2(double x1, double x2);	/*--プロトタイプ宣言--*/

#define R 1
#define L 1
#define C 0.3
#define E 1

#define limit 10
#define step 0.001

main()
{
        FILE *fp1;
        fp1=fopen("RLCF.txt","w");      /*--出力ファイル:RLCF.txt--*/

        double t,last_t;
        double x1,next_x1,x2,next_x2;
        double x1_k1,x1_k2,x1_k3,x1_k4;
        double x2_k1,x2_k2,x2_k3,x2_k4;

        x1=E;
        x2=0;

        for(t=0;t<limit;t=t+step){                                                                                                                                                                                      /*--以下、ルンゲ・クッタルーチン--*/
                x1_k1=step*f1(x1,x2);
                x1_k2=step*f1(x1+x1_k1/2.0,x2+x2_k1/2.0);
                x1_k3=step*f1(x1+x1_k2/2.0,x2+x2_k2/2.0);
                x1_k4=step*f1(x1+x1_k3,x2+x2_k3);
                                                        
                x2_k1=step*f2(x1,x2);
                x2_k2=step*f2(x1+x1_k1/2.0,x2+x2_k1/2.0);
                x2_k3=step*f2(x1+x1_k2/2.0,x2+x2_k2/2.0);
                x2_k4=step*f2(x1+x1_k3,x2+x2_k3);
                                                        
                next_x1=x1+(x1_k1+2.0*x1_k2+2.0*x1_k3+x1_k4)/6.0;
                next_x2=x2+(x2_k1+2.0*x2_k2+2.0*x2_k3+x2_k4)/6.0;
                x2=next_x2;
                x1=next_x1;

                fprintf(fp1,"%f %e\n", t, x1);
         }
                                                                        
         fclose(fp1);
}


double f1(double x1, double x2)                                         /*--f1の実体--*/
{
        double fx;
        fx = x2;
        return fx;
}

double f2(double x1, double x2)                                         /*--f2の実体--*/
{
	double fx;
	fx =(-(R*C*x2+x1)/(L*C));
	return fx;
}

------------------------------------------------------------------------------------
/*サンプル2*/
#include<stdio.h>
#include<math.h>

#define R 1
#define L 1
#define C 0.3
#define E 1
#define f1(x1,x2) (x2)                       /*--f1,f2をマクロで定義--*/
#define f2(x1,x2) (-(R*C*x2+x1)/(L*C))

#define limit 10
#define step 0.001

main()
{
FILE *fp1;
fp1=fopen("RLCF2.txt","w");			/*--出力ファイル:RLCF2.txt--*/

double t,last_t;
double x1,next_x1,x2,next_x2;
double x1_k1,x1_k2,x1_k3,x1_k4;
double x2_k1,x2_k2,x2_k3,x2_k4;

x1=E;
x2=0;

for(t=0;t<limit;t=t+step){																							/*--以下、ルンゲ・クッタルーチン--*/
x1_k1=step*f1(x1,x2);
x1_k2=step*f1(x1+x1_k1/2.0,x2+x2_k1/2.0);
x1_k3=step*f1(x1+x1_k2/2.0,x2+x2_k2/2.0);
x1_k4=step*f1(x1+x1_k3,x2+x2_k3);
x2_k1=step*f2(x1,x2);
x2_k2=step*f2(x1+x1_k1/2.0,x2+x2_k1/2.0);
x2_k3=step*f2(x1+x1_k2/2.0,x2+x2_k2/2.0);
x2_k4=step*f2(x1+x1_k3,x2+x2_k3);

next_x1=x1+(x1_k1+2.0*x1_k2+2.0*x1_k3+x1_k4)/6.0;
next_x2=x2+(x2_k1+2.0*x2_k2+2.0*x2_k3+x2_k4)/6.0;
x2=next_x2;
x1=next_x1;
fprintf(fp1,"%f %e\n", t, x1);
}
fclose(fp1);
}

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
サンプル1の出力結果(RLCF.txt)
0.000000 1.000000e+00
0.001000 9.999950e-01
0.002000 9.999867e-01
0.003000 9.999750e-01←違い
0.004000 9.999601e-01
0.005000 9.999418e-01
0.006000 9.999202e-01←違い
0.007000 9.998953e-01←違い
0.008000 9.998671e-01←違い
0.009000 9.998355e-01←違い
0.010000 9.998007e-01←違い
0.011000 9.997626e-01←違い
0.012000 9.997212e-01←違い
0.013000 9.996765e-01←違い
0.014000 9.996285e-01←違い
0.015000 9.995773e-01←違い

サンプル2の出力結果(RLCF2.txt)
0.000000 1.000000e+00
0.001000 9.999950e-01
0.002000 9.999867e-01
0.003000 9.999751e-01
0.004000 9.999601e-01
0.005000 9.999418e-01
0.006000 9.999203e-01
0.007000 9.998954e-01
0.008000 9.998672e-01
0.009000 9.998357e-01
0.010000 9.998010e-01
0.011000 9.997629e-01
0.012000 9.997215e-01
0.013000 9.996769e-01
0.014000 9.996290e-01
0.015000 9.995778e-01



No.3589

Re:#defineマクロで値が変わる?
投稿者---kikk(2002/11/26 23:46:21)


ども。


> #define f2(x1,x2) (-(R*C*x2+x1)/(L*C))



#define f2(x1,x2) (-(R*C*(x2)+(x1))/(L*C))

に変えればいいはずです。


BCCを使っているとのことですが、BCCの場合、プリプロセス文が
どのように処理・展開されたかは、

cpp32 sourcefile.c

として生成される sourcefile.iというファイルで確認できますので、
それを見て、なぜ、かっこがないとだめなのかを検証してみてください。
マクロのかっこはくどいくらいに付けたほうが無難です(特に引数は必ず)。
ちなみに、cpp32はBCCのプリプロセッサそのものです。

引数つきマクロでいろいろ悩みたくないが、オーバーヘッドはなくしたい
場合は、関数の前に inlineと書いた上で、C++としてコンパイルするのも
ひとつの手です。
# 最新のCの規格であるC99でも採用されたことですし


あと、これはマクロとは直接関係ありませんが。
数値計算のプログラムの場合、意味的に実数値の定数は、それがたとえ
整数だとしても実数であることを明示的にしておいたほうがいいです。
C言語ではコード中に整数があった場合は整数型として扱いますので、
0.5のつもりで1/2と書いてハマるというような可能性があります。
明示的に実数であることを表すには、キャストするか、f等の接尾子を
つけるか、1.0のようにするかしてください(場合によっては精度に注意)。


ついでに。問題点とは関係ありませんが、ソース全部を貼るのでしたら、
コンパイル時のエラーや警告はでないものにしてからのほうがよろしいかと。。


では。

No.3609

ありがとうございます(*^-^*)
投稿者---rolo(2002/11/27 21:10:58)


kikk様ご回答ありがとうございます(*^-^*)
ご回答のみならず、ご丁寧な解説まで・・・申し訳ありませんです。
なるほど、#defineマクロは特有のクセがあるようですね。奥が深い・・・(^^;
書籍等ではここまで詳しく解説してはくれていないので大変助かりました。
ありがとうございました!
P.S.
コンパイル時の警告については以後気をつけます。すみませんでした。