数値解析に関する質問

このQ&Aのポイント
  • 数値解析に関する質問について回答してくれませんか?
  • 以下のプログラムについて、初項の絶対値が大きい方の式を選んで消去する理由と、2元1次連立方程式の解が得られないデータを入力した場合のエラー表示について教えてください。
  • プログラムの実行結果は、x0=2, x1=3であり、チェックの結果も正しいようです。
回答を見る
  • ベストアンサー

数値解析に関する質問です

以下のプログラムにおいて 1) 初項の絶対値が大きい方の式を選んで消去する理由は何故か? 2)2元1次連立方程式の解が得られないデータ(例えば,1 2 3と2 4 6)を入力した場合,エラーを表示するようにするにはどうすればよいか? 教えてください。 よろしくお願いします。 #include <stdio.h> #include<math.h> //-------------------------------- void inputdata(double [2][3]); void calsol(double [2][3], double [2]); void elimination(double [2][3], double [2][3]); void outputdata(double [2]); void checksol(double [2][3], double [2]); //--------------------------------- main() { double c[2][3], x[2]; printf("Program of Gaussian elimination \n"); inputdata(c); calsol(c, x); outputdata(x); checksol(c, x); return(0); } //----------------------------- void inputdata(double c[2][3]) { printf("----------------------\n"); printf("Input Data\n"); printf("(a0*x0 + a1*x1 = a2)\n"); printf("\n"); printf("Equation 1\n"); printf("Input a0 a1 a2\n"); scanf("%lf%lf%lf" , &c[0][0], &c[0][1], &c[0][2]); printf("Equation 2\n"); printf("Input b0 b1 b2\n"); scanf("%lf%lf%lf", &c[1][0], &c[1][1], &c[1][2]); } //----------------------------- void calsol(double c[2][3], double x[2]){ double cc[2][3]; elimination(c, cc); x[1]=cc[1][2]; x[0]=cc[0][2]-cc[0][1]*x[1]; } //----------------------------- void elimination(double c2[2][3],double cc[2][3]) { int imax; double c1[3]; if(fabs(c2[0][0])>fabs(c2[1][0])){ imax = 0; } else{ imax = 1; } cc[0][0] = 1; if (imax == 0){ cc[0][1]= c2[imax][1]/c2[imax][0]; cc[0][2]=c2[imax][2]/c2[imax][0]; } else{ cc[0][1]=c2[1][1]/c2[1][0]; cc[0][2]=c2[1][2]/c2[1][0]; c1[0]=0; c1[1]=c2[0][1]-(cc[0][1]*c2[0][0]); c1[2]=c2[0][2]-(cc[0][2]*c2[0][0]); } cc[1][0]=c1[0]; cc[1][1]=1; cc[1][2]=c1[2]/c1[1]; } //----------------------------- void outputdata(double x[2]){ printf("--------\n"); printf("Solutions\n"); printf("x0=%14.6e\n", x[0]); printf("x1=%14.6e\n", x[1]); } //----------------------------- void checksol(double check [2][3],double x[2]) { double crt, clt; int ie; printf("---------\n"); printf("Check Solutions\n"); printf("Left Term Right Term\n"); for(ie=0; ie<=1; ie++) { clt = check[ie][0]*x[0] + check[ie][1]*x[1]; crt = check[ie][2]; printf("%14.6e %14.6e\n", clt,crt); } } 実行結果 Program of Gaussian elimination ---------------------- Input Data (a0*x0 + a1*x1 = a2) Equation 1 Input a0 a1 a2 2 3 13 Equation 2 Input b0 b1 b2 4 8 32 -------- Solutions x0= 2.000000e+00 x1= 3.000000e+00 --------- Check Solutions Left Term Right Term 1.300000e+01 1.300000e+01 3.200000e+01 3.200000e+01

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

  • ベストアンサー
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

このプログラムがどういうプログラム化を書いてくれた方がいいんだけど, 要は「連立 1次方程式を (ピボット選択を行う) ガウスの消去法で解く」ということでしょうか. であれば, 質問1 に対する回答は簡単で「その方が得られる解の精度がよくなるから」です.... といってもこの辺の詳しい説明はできないので「ガウスの消去法 ピボット選択」あたりで検索してください. また, このことから質問2 に対する回答も得られて, 「選ばれたピボットの値が 0 であれば元の係数行列の行列式は 0」です. したがって, そのときに「解が無限に存在するか全く存在しないか」のどちらかになります. まあ, 挙げられた例は「解が存在しない」場合じゃないんだけどね. あと, 敵は浮動小数なので「0 かどうか」という比較は本質的に無意味に近いことにも注意.

関連するQ&A

  • 数値解析に関する質問です

    以下のプログラムでは、関数pivotは,3つの引数を利用しているが,これを2つに減らす方法はないか? 教えてください。よろしくお願いします。 /*Gaussian Elimination*/ #include <stdio.h> #include <math.h> /*--------------*/ void inputdata(double [3][4]); void calsol(double [3][4],double [3]); void elimination(double[3][4],double[3][4]); void pivot(int *, double [3][4],int *); void outputdata(double [3]); void checksol(double [3][4], double [3]); /*--------------*/ main(){ double c[3][4], x[3]; /*-----------------------*/ printf("Program of Gauss Elimination\n"); /*-----------------------*/ inputdata(c); /*-----------------------*/ calsol(c,x); /*-----------------------*/ outputdata(x); /*-----------------------*/ checksol(c,x); /*-----------------------*/ return(0); } /*-----------------------*/ void inputdata(double c[3][4]){ int ie,ic; printf("------\n"); printf("Input Data\n"); printf("(a0*x0 + a1*x1 +a2*x2 = a3)\n"); printf("\n"); for(ie=0; ie<=2; ie++){ printf("Equation %d\n",ie); printf("Input a0 a1 a2 a3\n"); for(ic=0;ic<=3;ic++){ scanf("%lf", &c[ie][ic]); } } } /*-----------------------*/ void calsol(double c[3][4], double x[3]){   double cc[3][4]; elimination(c,cc); x[2]=cc[2][3]; x[1]=cc[1][3]-cc[1][2]*x[2]; x[0]=cc[0][3]-cc[0][2]*x[2]-cc[0][1]*x[1]; } /*-----------------------*/ void elimination(double c3[3][4], double cc[3][4]){ int ie,imax,eli; double c2[3][4],c1[3][4]; eli = 0; pivot (&eli,c3,&imax); cc[0][0]=1; cc[0][1]=c3[imax][1]/c3[imax][0]; cc[0][2]=c3[imax][2]/c3[imax][0]; cc[0][3]=c3[imax][3]/c3[imax][0]; for(ie=0;ie<=2;ie++){ if(ie != imax){ c2[ie][0]=0; c2[ie][1]=c3[ie][1]-cc[0][1]*c3[ie][0]; c2[ie][2]=c3[ie][2]-cc[0][2]*c3[ie][0]; c2[ie][3]=c3[ie][3]-cc[0][3]*c3[ie][0]; } } eli = 1; pivot(&eli,c2,&imax); cc[1][1]=1; cc[1][2]=c2[imax][2]/c2[imax][1]; cc[1][3]=c2[imax][3]/c2[imax][1];   for(ie=0;ie<=1;ie++){ if(ie !=imax){ c1[0][2]=c2[ie][2]-cc[1][2]*c2[ie][1]; c1[0][3]=c2[ie][3]-cc[1][3]*c2[ie][1]; } } cc[2][2]=1; cc[2][3]=c1[0][3]/c1[0][2]; } /*-----------------------*/ void pivot(int *eli,double c[3][4],int *imax){ int ie; double cmax; if(*eli ==0){ cmax=0; for(ie=0;ie<=2;ie++){ if(fabs(c[ie][0])>cmax){ cmax=c[ie][0]; *imax=ie; } } } else{ cmax=0; for(ie=0;ie<=1;ie++){ if(fabs(c[ie][1])>cmax){ cmax=c[ie][1]; *imax=ie; } } } } /*-----------------------*/ void outputdata(double x[3]){ int i; printf("------\n"); printf("Solutions\n"); for(i=0;i<=2;i++){ printf("x%d=%14.6e\n",i,x[i]); } } /*-----------------------*/ void checksol(double check[3][4],double x[3]){ double crt,clt; int ie,ic; printf("------\n"); printf("Check Solutions\n"); printf("Left Term Right Term\n"); for(ie =0;ie<=2;ie++){ clt =0 ; for(ic=0;ic<=2;ic++){ clt = clt + check[ie][ic]*x[ic]; } crt = check[ie][3]; printf("%14.6e%14.6e\n",clt,crt); } }

  • 数値解析に関する質問です。

    数値解析に関する質問です。 以下のプログラムでは、4元1次連立方程式のデータは、cとcheckの2つの配列に入力される。この理由を教えてください。また、1つの配列に入力して済ませる方法を教えてください。 よろしくお願いします。 /*kadai 13 Gaussian Elimination Method for System of Linear Equations*/ #include <stdio.h> #include<math.h> /*---------------------------*/ void inputdata(double[4][5],double [4][5]); void calsol(double [4][5],double [4]); void elimination(double [4][5], double [4][5]); void pivot(int *, double [4][5], int *); void outputdata(double [4]); void checksol(double [4][5],double [4]); /*---------------------------*/ main(){ double c[4][5], check[4][5],x[4]; /*---------------------------*/ printf("Program of Gaussian Elimination Method 3\n"); /*---------------------------*/ inputdata(c, check); /*---------------------------*/ calsol(c,x); /*---------------------------*/ outputdata(x); /*---------------------------*/ checksol(check, x); /*---------------------------*/ return(0); } /*---------------------------*/ /* Function inputdata */ /*--------------------------*/ void inputdata(double c[4][5],double check[4][5]){ int ie,ic; printf("-----\n"); printf("Input Data\n"); printf("(a0*x0 + a1*x1 + a2*x2 +a3*x3 = a4)\n"); printf("\n"); for(ie=0; ie<=3; ie++){ printf("Equation %d\n",ie); printf("Input a0 a1 a2 a3 a4\n"); for (ic=0; ic<=4; ic++){ scanf("%lf",&c[ie][ic]); check[ie][ic] = c[ie][ic]; } } } /*---------------------------*/ /* Functiom calsol */ /*---------------------------*/ void calsol(double c[4][5],double x[4]){ double cc[4][5]; elimination(c, cc); x[3]=cc[3][4]; x[2]=cc[2][4]-cc[2][3]*x[3]; x[1]=cc[1][4]-cc[1][3]*x[3]-cc[1][2]*x[2]; x[0]=cc[0][4]-cc[0][3]*x[3]-cc[0][2]*x[2]-cc[0][1]*x[1]; } /*---------------------------*/ /*Function elimination */ /*---------------------------*/ void elimination(double c[4][5],double cc[4][5]){ int ie,ic,ienew,imax,eli; eli = 0; while(eli<4){ pivot(&eli,c,&imax); cc[eli][eli] = 1; for(ie=eli+1;ie<=4;ie++){ cc[eli][ie]=c[imax][ie]/c[imax][eli]; } ienew= 0; for(ic=0;ic<=3-eli;ic++){ if(ie != imax){ for(ie=eli+1;ie<=4;ie++){ c[ienew][ie]=c[ic][ie]-cc[eli][ie]*c[ic][eli]; } ienew = ienew + 1; } } eli = eli +1; } } /*---------------------------*/ /*Function pivot */ /*---------------------------*/ void pivot(int *eli,double c[4][5],int *imax){ int ie; double cmax; cmax=0; for(ie=0;ie<=4-*eli;ie++){ if(fabs(c[ie][*eli])>cmax){ cmax=fabs(c[ie][*eli]); *imax=ie; } } } /*---------------------------*/ /*Function outputdata */ /*---------------------------*/ void outputdata(double x[4]){ int i; printf("------\n"); printf("Solutions\n"); for(i=0;i<=3;i++){ printf("x%d=%14.6e\n",i,x[i]); } } /*---------------------------*/ /*Function checksol*/ /*---------------------------*/ void checksol(double check[4][5],double x[4]){ double crt,clt; int ie,ic; printf("-------\n"); printf("Check Solutions\n"); printf("Left Term Right Term\n"); for(ie=0;ie<=3;ie++){ clt = 0; for(ic =0;ic<=3;ic++){ clt = clt + check[ie][ic]*x[ic]; } crt = check[ie][4]; printf("%14.6e %14.6e\n",clt,crt); } }

  • 数値解析に関する質問です。

    /*kadai8 Euler’s Method for Ordinary Differential Equation */ #include <stdio.h> void euler(double *, double *); main () { int i; double v,t,tt,dt[5]; dt[0] = 2; dt[1] = 1; dt[2] = 0.1; dt[3] = 0.01; dt[4] = 0.001; printf("Program of Euler`s Method 1\n"); printf("-----------------------------------------\n"); tt = 50.0/9.80665; printf("Theoretical Solution : %lfs\n",tt); for(i=0;i<=4;i++){ printf("--------------------------------\n"); printf("Step Size : %lf s\n",dt[i]); v=50.0; t=0.0; while(v>0) { euler(&v,&dt[i]); t=t+dt[i]; } printf("Numerical Solution : %lf s\n",t); printf("Error : %lf s\n",t-tt); } return(0); } /*--------------*/ void euler(double *v,double *dt) { *v=*v + (*dt )*(-9.80665); } 以上のプログラムで関数eulerの引数にポインタがついているのはなぜか,またポインタを使用しない方法はないか?また、オイラー法より精度の高い解法はありますか? よろしくお願いします。

  • 数値解析法

    このHeun法のプログラムをRunge-Kutta法にするにはどうしたらいいですか? #include <stdio.h> #include <math.h> double f1(double y) { return y; } double f2(double y) { return -4*y; } int main(){ double a=0; double b; int m=10; int n; double h; double x,y; int k; double e; double f; double k1,k2; printf("Heun法計算例:y=e^x, y=1/e^4x\n\n"); // y = e^x b = 1; for(n=100;n<=10000;n*=100){ h = (b-a)/n; printf("y' = y: h(=dx) = %.1e (y=e^x)\n",h); x = a; y = 1; for(k=0;k<=n;k++) { x = k*h; if(k%(n/m)==0) { f = exp(x); e = fabs(y-f); printf("x=%.2f, y=%f, e^x=%f er=%.0e\n",x,y,f,e); } // Heun's method k1 = h*f1(y); k2 = h*f1(y+k1); y += (k1+k2)/2; } }

  • 二分法のプログラムについて

    下の用なプログラムを作ったのですがどうしても正しい答えを導くことができません。自分でもいろいろ調べてみましたがわかりません。誰かご教授宜しくお願いします。 #include<stdio.h> #include<stdlib.h> #define MAX 10 int n , count; double c[MAX+1]; double a,b,e; void nyuuryoku(void) { int i; printf("nの入力>"); scanf("%d",&n); if(n>MAX){printf("最大次数を超えている");exit(1);} else if(n<0){printf("nが負");exit(2);} else{for(i=0;i<=n;i++){printf("係数の値>");scanf("%lf",&c[i]);} }} double f(double x) {double y; int i; y = c[0]; for(i=1;i<=n;i++){ y=y*x+c[i];} return y; } void hani(void){ printf("aの値>");scanf("%lf",&a); printf("bの値>");scanf("%lf",&b); printf("eの値>");scanf("%lf",&e); if(e<=0){printf("eが0または負"); exit(3);} if(f(a)==0){printf("%f",f(a)); exit(4);} if(f(b)==0){printf("%f",f(b)); exit(5);} if(f(a)*f(b)>0){printf("初期値異常"); exit(6);}} double nibun(void) {double c; if(b>a){ while(b-a>e){ count++; c=(a+b)/2; if(f(c)==0){ return c;} if(f(a)*f(c)<0){b=c;} if(f(b)*f(c)<0){a=c;} } return a;} if(a>b){ while(a-b>e){ count++; c=(a+b)/2; if(f(c)==0){ return c;} if(f(b)*f(c)<0){a=c;} if(f(a)*f(c)<0){b=c;} } return a;} } void syutsuryoku(double x){ printf("x=%lf\n",x); printf("f(x)=%lf\n",f(x)); printf("繰り返し回数=%d\n",count); } int main(void){ double ans; count=0; nyuuryoku(); hani(); ans = nibun(); syutsuryoku(ans); }

  • C言語で計算が合いません(初心者)

    C言語で計算が合いません(初心者) 簡単な計算のプログミングをしているのですが 計算が合わなくて困っています。 整数型変数aと実数型変数bを定義 整数型変数cとdを定義して、c=0.5*a*b、d=a/2*b 実数型変数eとfを定義して、e=0.5*a*b、f=a/2*b という内容のプログラムを作ったのですが a=7,b=2.4を代入してみた結果 ---------------------------- Input a>>7 Input b>>2.4 8 7 8.400000 7.200000 ---------------------------- となりました どこが間違っているのでしょう? 答えは8.4でcが8なのは有効数字のためだと思いますが dとeで答えが全く違う理由が分かりません。 下に私が書いたものを貼っています。 ---------------------------- #include<stdio.h> int main(void){ int a,c,d; double b,e,f,ans; printf("Input a>>"); scanf("%d",&a); printf("Input b>>"); scanf("%lf",&b); c=0.5*a*b; printf("%d\n",c); d=a/2*b; printf("%d\n",d); e=0.5*a*b; printf("%lf\n",e); f=a/2*b; printf("%lf\n",f); return 0; } ---------------------------- よろしくお願いします。

  • C++でのプログラムについての質問です

    このような二次関数の解を求めるプログラムを作成したのですが、自作関数solveをvoid solve(double, double, double)のように変更し同じ動作をするように変更したいです どのようにへんこうすればよいでしょうか #include<stdio.h> #include<stdlib.h> #include<math.h> int main(void) { double a, b, c; /*二次方程式の定数*/ double D, x1, x2, r1, r2; printf("ax^2 + bx + c = 0 の係数 a, b, c を入力してください---> \n"); scanf_s("%lf %lf %lf", &a, &b, &c); printf("2次方程式を解いた結果は次の通りとなる。\n"); if (a == 0.0) { if (b == 0.0) { printf("係数がおかしい\n"); exit(-1); } { x1 = -c / b; printf("解は%f です。\n", x1); exit(0); } } else { D = b * b - 4 * a * c; if (D >= 0) { x1 = (-b + sqrt(D)) / (2.0 * a); x2 = (-b - sqrt(D)) / (2.0 * a); if (D == 0.0) { printf("解は %f です。\n", x1); } else { printf("解は %f と %f です。¥n", x1, x2); } } else { r1 = -b / (2 * a); r2 = sqrt(-D) / (2 * a); printf("解は%.2f+%.2fi と%.2f-%.2fi \n", r1, r2, r1, r2); } } return 0; }

  • 関数呼び出しを使った、絶対値出力プログラムについて質問です。

    すみませんが、このプログラムを見てもらえませんか? 絶対値が上手く表示できません。よろしくお願いします。 #include <stdio.h> double myabs(double); main() { double x,a; printf("Input number = "); scanf("%lf", &x); if(x < 0) { a = myabs(x); printf("Zetaitti = %f\n", a); } else { printf("Zetaitti = %f\n", x); } } double myabs(double x) { double a; x = -x; return(a); }

  • 値の渡し方?(初心者)

    以前質問したプログラムについて、新たに質問です。 メインプログラムと、関数プログラムを組みました。 関数の中では、print文を使うと計算は正しく行われていて、結果が正しいことが分かりました。 でうが、メイン文の出力では、どこにも出てこない変な値が出てきてしまいます。 値の渡し方がおかしいのでしょうか? 誰か、アドバイスをお願いします。 ***以下プログラムです。*** #include <stdio.h> #include <math.h> double gamma(double x) { double c[9],y,a,r,b,s,z; int i; a=1.; r=1.; c[1]=5.771916e-01; c[2]=9.882058e-01; c[3]=8.970569e-01; c[4]=9.182068e-01; c[5]=7.567040e-01; c[6]=4.821993e-01; c[7]=1.935278e-01; c[8]=3.586834e-02; printf("0 %f\n",x); while(1){ if(x>2.){ x=x-1.; a=a*x; printf("1 %f %f\n",x,a); } else if(x<1.){ a=a/x; x=x+1.; printf("2 %f %f\n",x,a); } else{ break; } } x=x-1.; for(i=1;i<9;i++){ b=(double)(i); s=(c[i]*((double)(pow(-1.,b)))*((double)(pow(x,b)))); printf("3 %d %f\n",i,c[i]); r=r+s; } y=a*r; printf("4 %lf\n",y); return y; } main() { double x,y; printf("数字を入力してください。"); scanf("%lf",&x); printf("メインプログラム x= %lf \n",x); y=gamma(x); printf("x= %f y= %f\n",x,y); }

  • C言語の質問です

    ニュートン法のプログラムを組んだのですがPAD図が描けなくて困ってます どなたか回答お願いします /* newton.c: ニュートン法 */ #include <stdio.h> // printf, fprintf, fgets, sscanf #include <math.h> // fabs double a;    //グローバル変数 double f(double x)  //fは関数f(x) { return x * x - a; //f(x)=x~2-a } double df(double x)  //dfはf(x)の導関数f’(x) { return 2 * x; //df(x)/dx = 2x } double newton(double x, double (*f)(double), double (*df)(double), double eps) { int n = 0;     //初期化 double x0, err;    //x0は初期値 printf("# n, x, err\n"); printf("%4d, % .15e\n", n, x); do { n++; x0 = x; x = x0 - f(x0) / df(x0); //切片でy=0、x=x1 err = fabs(x-x0); printf("%4d, % .8e, % .15e\n", n, x, err); } while (err >= eps); return x; } /*メインルーチン*/ int main(void) { double x, eps = 1.0e-10; //収束条件 char s[128]; fprintf(stderr, " a = "); fgets(s, 128, stdin); sscanf(s, "%lf", &a); while (a <= 0.0) { fprintf(stderr, "'a' には正の数を入れてください。\n"); fprintf(stderr, " a = "); fgets(s, 128, stdin); sscanf(s, "%lf", &a); } x = (a + 1.0) / 2.0; x = newton(x, f, df, eps);   //ニュートン法の実装 printf("\n# √(%e) = % .15e\n", a, x); return 0; }

専門家に質問してみよう