• ベストアンサー

引数の個数を変えないで変数(定数)を扱う

別に積分に限らないと思うのですが、積分を例にして質問させていただきます。 次のようなルーチンがあります。 integral( double (*func)(double), double a, double b ); /* a~bまで関数funcを積分する。 */ そこで、簡単に被積分関数を fx=3*x とすれば、 double fx(double x) { return 3*x; } というようにすれば良いですよね。 でも、例えば fx = exp(x-X) とか fx = x*X のような関数を積分したいときはどうすればよいのでしょうか? Xは変数ですが、xにはよらないので積分の中では定数とみなせます。 ループで X=0 のときにfxを積分 X=1 のときにfxを積分 X=2 のときにfxを積分… というようにしたいのですが、 fxの引数をfx(double x, double X) とすると、プロトタイプ宣言もルーチンの中も書き換えなければならなくなりますよね。 さらに fx = x-X + x' などとなったりすると、さらに書き換えなければならなくなり、せっかくの積分のルーチンをうまく使えません。 Xをグローバルで宣言する方法と、 プログラミングの前に、x-X を x' などと置きかえた式を実際に手計算で作る方法を思いついたのですが、 グローバル変数を使うのはあまりよくないし、手計算では簡単な場合しか置換を思いつかなかったりします。 fxの中で X を宣言して、 double fx(double x) { static double X; double y; y = x-X; X++; return y; } という方法も考えたのですが、どうもイマイチ良くないような… こういう場合に、良い方法はありますか? ここには簡単な関数を書きましたが、少し複雑な関数を積分するので。 質問の意図がうまく伝わらなかったらすいません。 書きにくかったです。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.4

> fxの中の *(double*)params > がどういう扱い方をしているのか教えていただけないでしょうか? たとえば f(x) = x * X で X が 3.0 のとき、integral を使うには: double f(double x, void* params) { double X = *(double*)paramsl return x * X; } ... double X = 3.0; double result = integral(f, &X, a, b);

yassan_yassan
質問者

お礼

いろいろありがとうございました。

その他の回答 (3)

  • bikkuri
  • ベストアンサー率33% (23/68)
回答No.3

現状から大きく変わるので、単なる案です。 C++もありと考えると、積分関数を定義して渡すのではなく、 関数をメソッドとして実装している関数オブジェクトを integral関数に渡すと、面白いかもしれません。 ・実行しようとする関数のオブジェクトを生成 ・定数など必要な物をオブジェクトに設定 ・integralにオブジェクトと範囲a,bを渡す ・integralでは、オブジェクト内の関数メソッドをcall(名前は固定) ・関数オブジェクトではパラメータxと内部の定数で値を返す みたいな感じです。 Cでも、構造体(or共用体)で似た実装をすることは可能でしょう。 (構造体中に関数ポインタと定数メンバを設ける感じ)

  • ranx
  • ベストアンサー率24% (357/1463)
回答No.2

integralのインターフェースを変えないという前提で考えると、 外部static変数を使うのはどうでしょう。 static double X; double fx(double x) { ・・・ } void setParameter(double p) {  X = p; } というようにしておけば、Xはこのソースファイルの外からは直接アクセスできません。 integralを呼び出す前に予めsetParameterでXをセットしておきます。

yassan_yassan
質問者

お礼

回答ありがとうございます。 外部staticを使うのですか。 考慮してみます。

回答No.1

僕ならこうする: integral( double (*func)(double,void*), void* params, double a, double b ); { ... (*func)(x,params); ... } double fx(double x, void* params) { double X = *(double*)params; ... } void* params を介して受け渡します。

yassan_yassan
質問者

お礼

回答ありがとうございます。 でも、すいません。 初心者なので、このプログラムがよく分からないです。 (*func)(double, void*), void* params, の宣言は何を意図しているのか。 fxの中の *(double*)params がどういう扱い方をしているのか教えていただけないでしょうか? すいません。

関連するQ&A

  • 使い回しの効く関数の作り方

    ある関数をaからbまで積分する関数integralがあります. integral(double (*func)(double, void*), void* t, double a, double b) 例えば次の関数 fx=5x double fx(double x, void* y0) { double y =*(double*)y0; return y*x; } を積分するときには double y=5.0; integral(fx, &y, 1.0, 5.0); としています. さらに gx=5x+5 のようなときは, 構造体を宣言して double gx(double x, void* y0) { parameter p =*(parameter*)y0; return p.y*x + p.z; } としています. これはいい方法なのでしょうか? 関数funcの引数の数を変えてしまうと, integralの使い回しができなくなると思い, このような方法にしていますが, これも被積分関数ごとに構造体を用意しなければならず, あまり良くないんじゃないかな~って思っています. もっといい方法があれば教えていただきたいです. よろしくお願いします.

  • main関数の中でパラメータを宣言

    c言語で積分をしています。 a~bまで積分する関数を dobule integral(double (*f)(double), double a, double b) { ・・・・・・ return s; /*sが計算結果*/ } としています。 fx=x*x を積分するときは double fx(double x) { return x*x; } を用意して、 main() { double ans = integral(fx, 0.0, 1.0); } という具合で現在やっています。 本題なのですが、 main関数の中でxを宣言して、そのxで同じように積分をしたいのです。 どうすればよいのでしょうか? 良い方法があれば教えて頂きたいです。

  • 関数の掛け算を返す関数

    いま関数の積分を行おうとしています. この積分を行う関数が double integral(double (*func)(double), double a, double b ) {    double ans;    .....    return ans; } となっていて,aからbまでfuncが指す関数を積分して結果を返します. 積分をさせる関数は double f1(double x) { return 3.0*x; } double f2(double x) { return x*x; } となっていて,同じようにg1, g2も用意します.(本当は関数が3つ4つあります.) 例えばf1を積分したいとき, int main() {    double ans = integral(f1, a, b);    printf("%f\n", ans); } ですよね. 自分で積分する関数を選ぶときは,ここに配列で場合分けをして double (*func_f[])(double)={f1, f2}; scanf("%d", &flag); /* flagに0~1を代入 */ ans = integral(func_f[flag], a, b); でいいと思います. さて,そこで本題なのですが, double (*func_f[])(double)={f1, f2}; double (*func_g[])(double)={g1, g2}; としておいて, scanf("%d", flag1); scanf("%d", flag2); func_f[flag1], func_g[flag2]; として関数を入力側から決定して, (例えばflag1=1, flag2=1,であったとして *func_f[1]=x*x *func_g[1]=5.0*x ならば) h(x)=(x*x)*(5.0*x)=5.0*x*x*x という関数を作って, h(x)を指すポインタを double (*h_ptr)(double) とすれば ans = integral(h_ptr, a, b); としたいのです. (f1*g2)を一つの関数としてh(x)=(f1*g2)(x)というように扱うことができればいいと思うのですが. integralの引数で,関数のポインタを2個にすると,汎用性が失われてしまうと思うので,できればそこは変えたくないです. どのようにすればよいのでしょうか? また,「考え方を変えればよい」などの意見も頂きたいです. 皆様,どうぞよろしくお願いします.

  • 関数を引数とする方法?

    いつもお世話になっています。 MFCでプログラムをしています。 今、任意の関数(Func1)を 積分する関数(Func2)を作っています。 現在は、被積分関数の数だけ、 積分関数(Func2)を書いているのですが、 非効率的なので、なるべく汎用性を持たせたいと 考えています。 参考書(新C言語入門シニア編)の該当個所で、 クラスでない通常の関数を引数とする場合は、 うまくいったのですが、 クラスのメンバ関数を引数とした場合、 どうしてもコンパイルエラーが 発生してしまいます。 関数Func、I及びエラーメッセージは大凡次のとおりです。今のところ、引数とする関数(Func1)の引数は、 同一個数としています。 <被積分関数の例> double ClassA::Func1 (double a){ return a * 10; } <積分関数> double ClassA::Func2 (double (*f)(double), double a, double b){ return b * f(a); } void classA::Integration() { ... Func2(Func1,a,b); ... } <エラーメッセージ> classA::Integrationの呼び出し箇所で、 「1番目の引数を double(double)からdouble(__cdecl)(double)に 変換できません」 と出ます。 double(double)の部分は合っているようなのですが、 (__cdecl)の部分が違うということまでは 分かりました。 メンバ関数であることが原因のようなので、 Func2での引数宣言を double ClassA::Func2 (double (ClassA::*f)(double), double a, double b){ return b * f(a); } に変えてみたところ、 引数受け渡しのところはクリアするのですが、 Func2(Func1,a,b); の呼び出し時に、Func2が関数ではないという エラーがでます。 アドバイス又は参考URL等を 教えていただければ助かります。 よろしくお願いします。

  • 変数宣言にいらないの入れると正確な出力になる(なんかおかしいです

    main関数の中の double x,y; のままだと出力のout.txtは間違った答えになるのに double x,y,n;とか関係ない変数を宣言に足すと、 正解な値が出ます。 ソースはRunge-Kuttaの計算をするものです。 他はまったく変えてないのになぜ結果がちがくなるのでしょうか? おかしいとおもって友達などにも実行してもらったんですが同じ症状がでます。 環境はVC++6.0でOSはMEと2kとXPで試したんですが、同じ結果でした。 ソースは↓です。よろしくお願いします。 #include<stdio.h> #include<stdlib.h> #define X0 0.0 #define Y0 1.0 #define XEND 0.5 #define XSTEP 0.1 double func(double xx,double yy); main() { double x,y; double k[3]; FILE *fp1; if(!(fp1=fopen("out.txt","w"))){ printf("ファイルを開けません\n"); exit(1); } x=X0; y=Y0; for(x=X0;x<=XEND;x=x+XSTEP){ fprintf(fp1,"%f\t%f\t\n",x,y); k[0]=XSTEP*func(x,y); k[1]=XSTEP*func(x+XSTEP/2,y+k[0]/2); k[2]=XSTEP*func(x+XSTEP/2,y+k[1]/2); k[3]=XSTEP*func(x+XSTEP,y+k[2]); y=y+(k[0]+2*k[1]+2*k[2]+k[3])/6; } return 0; } double func(double xx,double yy) { return yy; }

  • 関数の引数と実引数の取り扱いについて

    C言語初心者です. 関数の引数と実引数の取り扱いについて,教えていただきたいことがあります. 例えば,2変数の和を求める関数を考えると,以下のようになると思います. #include <stdio.h> double sum(double x, double y); int main(void) { double a, b, wa; a=2.0; b=3.0; wa=sum(a,b); return 0; } double sum(double x, double y) { double total; total=x+y; return total; } このとき,mainプログラムでは,a,bふたつの変数を定義しておいて,関数sumに入れて計算させているわけですが,mainプログラムで変数x,yを定義しておいて,以下のようなプログラムにするのはありでしょうか? 参考書などをみると,前者のように取り扱っているようなのですが,試しに後者で実行させてみても同じ結果となりました. #include <stdio.h> double sum(double x, double y); int main(void) { double a, b, wa; a=2.0; b=3.0; wa=sum(a,b); return 0; } double sum(double x, double y) { double total; total=x+y; return total; }

  • C++:ある関数を定義するときに別の関数を用いて定義はできないのですか。

     Visual C++を使っています。  以下のように関数func2において関数func1を使いたいのですがコンパイルするとポインタがどうのこうのと言ってきます。  書き方が間違っているのでしょうか、別にいい方法がありましたら教えてください。参考書はありますので、どの項目を見ればよいと言うアドバイスでも結構です。 const double a=100.0; //グローバル変数aを定義 //関数func1を定義 double func1(double x){ return exp(x); } //関数func2を定義 double func2(double y){ return func1(a)*exp(y);//func(a)は係数。 } 実際はfunc1とfunc2はもっと複雑な形なのでどうしても別々に定義したいです。

  • 変数と定数について

    とても基本的な質問ですが、質問・確認させていただきたいです。 変数と定数の違いについて 例⑴ x,y:変数 a,b,c,m,n,l:定数とするとき、 y=f(x)=ax²+bx+c ・・・① y=g(x)=mx²+nx+l ・・・② の2つの放物線の形が違う2次関数があるとする。 ①と②は共に「y= より①と②は常に同じ値yである」ということにはならないですよね。 ですが、これが 例⑵ s:定数(x:変数 a,b,c,m,n,l:定数 ) とするとき、 s= ax²+bx+c ・・・③ s= mx²+nx+l ・・・④ と表すと、 こちらは有無を言わさず(?)「同じ文字である」=「同じ値sである」となり、xが決まります。 これは『変数y』と『定数s』の違いということでしょうか。 変数において「同じ文字である」=「同じ値である」とは言えないということですよね。 例⑴で変数y消去して①=②にする時は、y=p(p:定数)が存在するという扱いにして計算を進めているのでしょうか。 変数を文字消去する時(代入・足し引きして)は、その消去する変数をどのように扱っているのでしょうか。 初歩的な質問ですが、どなたかよろしくお願いいたします。

  • 関数の引数なしを変数に代入したら入ってきた数値は何?

    デバッグソフトで自分のプログラムを動かしていたときに、 int test_func(char x) { x = x + 1; ------(中略)----------- return x; } int main(void) { int test_val; ------(中略)----------- test_val = test_func; ------(中略)----------- } このようにtest_func(char x)という関数の戻り値を変数test_valに代入するつもりだったのですが、間違って引数部分を書かずにコンパイルしてしまいました。 このときにコンパイルでエラーが出ると思ったのですが、コンパイル完了でデバッガで変数test_valをみてみると何か値が入っていました。 ちょっと気になったのですが、この変数の中に入った値はいったい何なのでしょうか。ご存じの方いらっしゃいましたらご教授お願いいたします。

  • 関数へのポインタで

    関数を場合によって使い分けたくて, 次のようにしています. double f1(double x) { return 3*x; } double f2(double x) { return 5*x; } double f3(double x) { return 10*x } /* 同じようにg1, g2, g3があります. */ 次のようなルーチンを使って, void sub(double (*F)(double), ...) { F(a); F(b); } int main() { double (*func_f[])(double)={f1, f2, f3}; double (*func_g[])(double)={g1, g2, g3}; sub(func_f[i], ...) } といった感じにしています. いま,f1*g2のような関数に対してsubを使いたいのですが,この場合はどのようにすればいいのでしょうか? (f1*g2)を一つの関数として扱えることができればいいと思うのですが,方法がわかりません. 教えて下さい. よろしくお願いします.

専門家に質問してみよう