- ベストアンサー
C言語による数値計算の指導に関する質問
- C言語で2次関数の係数を求めるプログラムを作成したいが、ガウス消去法で解けない
- ガウス消去法を用いたC言語のプログラムを作成したがエラーが出ている
- 他の人が教えてくれることでプログラムが完成できるかどうか知りたい
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
- ベストアンサー
double *simple_gauss( double a[3][3], double b[3] ); などはこれでも正解なのですが、具体的な数値名が関数の定義に含んでいるので 本当はポインタであることを明確にするために double *simple_gauss( double **a, double *b ); などとするべきかなと思います。(その方が一々数字を書き換えなくていいですし) 後、細かいことではありますが、 double a[3][3]; /* マトリックスの宣言*/ double x[3]; /* 解ベクトルの宣言*/ double y[3]; /* 右辺ベクトルの宣言*/ double xx, yy; /* キーボード入力のための一時変数*/ の部分は個々の変数名が分かりにくいのも問題かなと思います。 私も昔はこういう書き方をしていましたが、エラーが出る可能性の増大が馬鹿に出来ないことに ある時気がつき、forループなどの一時的なカウンター変数を除いては一時的なものであっても 分かりやすい命名を心がけています。 さらに、これらの変数は見たところ共通している要素であるため、構造体、または C++であればクラスなどでパックにした方が後々の修正や読む人が楽であると思います。 最後に、コメントに /* コメント */ の方法を取っているようですが、これは単一の行で用いるにはあまり推奨されない方法です。 というのも/* */はその間に/* */をはさんでコメントアウトなどが出来ないので、 もしある関数の中身でコメントに/* */が多用されているとテストするときに ここからここまでコメントアウトしたい・・などというときに/* */を使って一気に コメントアウトしようとしても間に/* */が混じっているとコンパイルエラーになってしまい、 大規模なソフトを作る際にはかなり面倒が起こりやすいです。 初期のC言語では/* */が唯一のコメント方法であり、//コメント の形式はサポートされていませんでしたが、 現在は標準Cで//コメントの形式がサポートされているので、例えば double a[3][3]; /* マトリックスの宣言*/ double x[3]; /* 解ベクトルの宣言*/ double y[3]; /* 右辺ベクトルの宣言*/ double xx, yy; /* キーボード入力のための一時変数*/ は double a[3][3]; //マトリックスの宣言 double x[3]; //解ベクトルの宣言 double y[3]; //右辺ベクトルの宣言 double xx, yy; //キーボード入力のための一時変数 のようにした方が良いかと思います。 後、要素の数が3の配列が多いですが、これらは必ず3と固定されているのでしょうか? もし数学的な理由で3と固定されているなら #define ARY_NUM 3 などとして配列の宣言時は double a[ ARY_NUM ][ ARY_NUM ]; //マトリックスの宣言 double x[ ARY_NUM ]; //解ベクトルの宣言 double y[ ARY_NUM ]; //右辺ベクトルの宣言 double xx, yy; //キーボード入力のための一時変数 などとした方が色々な面で後の変更や修正が楽です (C++ならconst intでやる方法もあります) ところで自宅のPCにはVisual Studioを入れていないということでしたが、 http://www.microsoft.com/japan/msdn/vstudio/express/ 無料版があることは既にご存知でしょうか? おせっかいかもしれませんが、もしご存知でなければ本当に便利ですので導入をオススメします。 (私もCやC++で3Dのプログラム組む時などはこれが手放せないです)
その他の回答 (1)
私には数学の知識が中卒程度しかないのでプログラム部分だけアドバイスを ・main(void)はint main( void )と書くべき ・simple_gauss関数でfor( i = k+1; i <= ; i++)となっている(タイプミスでは? ・ y=*simple_gauss(a,y);は定義済みのyに配列確保しようとしています。 mallocするかあるいはdouble * y2 = simple_gauss( a, y );のように新しい配列を確保しなおす必要があります。 これを修正したらコンパイルは通りましたが、これはあまり良いコードとは思えません。
お礼
スペースを空けたのに何故か全部左詰めになって見にくくてすみません。 あまりよいコードではないとは? 点(x,y)を5点キーボード入力してa,b,cがでればいいのですが.... すんません、今返信してるパソコンにはWindowsVisualStudio等のコンパイラがないので大学のパソコンでしか動作確認ができない状態なんですがOTLすいません。
補足
すみませ~ん!ガウス消去法の部分がちょっと間違ってました { int i, j, k; double alpha, tmp; /* 前進消去 */ for( k = 1; k <= 2; k++) { for( i = k+1; i <= 3 ; i++) { alpha = - a[i][k]/a[k][k]; for( j = k+1; j <= 3; j++) { a[i][j] = a[i][j] + alpha * a[k][j]; } y[i] = y[i] + alpha * y[k]; } } /* 後退代入 */ y[3] = y[3]/a[3][3]; for( k = 2; k >= 1; k--) { tmp = y[k]; for( j = k+1; j <= 3; j++) { tmp = tmp - a[k][j] * y[j]; } y[k] = tmp/a[k][k]; } return y; } です 仰るとおりタイプミスも修正しましたが....
お礼
Visual Studioの情報ありがとうございます aが3×3の行列なので、縦横の順にa[3][3]とおきました 対応してx、yは3×1行列なのでx[3]、y[3]とおきました a×x=yの関係です 求めるa,b,cと行列aが同じに見えてややこしいのでp,q,rに変えますね、すいません 要は以下の連立方程式を行列化しただけなのですが p×Σxi^4+q×Σxi^3+r×Σxi^2=Σxi^2*yi p×Σxi^3+q×Σxi^2+r×Σxi=Σxi*yi p×Σxi^2+q×Σxi+r×5=Σyi 見ての通りこれを行列化しa×x=yにするとaがややこしくなるのでa[1][1]=~,a[1][2]=~....と成分を書き出しました main(void)内で5点の座標(x,y)をキーボード入力して、その後の計算して表示double *simple_gaussで計算した結果を表示してくれればいいのですが それで http://www.ma.is.saga-u.ac.jp/minamoto/book/book8/book8.html の本を授業で使ってまして、これの第3章3.1のプログラムをもとに作成したのですが、これはinput.dat等のファイルから展開して計算をしているのですがこれをscanfで直接5点の座標(x,y)をキーボード入力して取り込みそれをもとに計算するように変えようとして失敗したのが始めに投稿したプログラムです ガウス消去法の部分はそのまま使えるのでmain(void)部分内を何とか変えることができたらと思うんですが ちなみに/* コメント */もこの本を参考にしているので詳しいことは知りませんでした、全くの素人なんでfatalitaさんのような専門の人に質問を回答いただいて本当に感謝しています