• ベストアンサー

Visual C++での数値計算のプログラミング

質問初めてになります。 プログラミングにあまり詳しくない大学院の数理科の学生です。 学校で熱方程式の陽解法のプログラミングのレポートが出されたのですが、困っています。 レポートで詰まっている点は windows Visual C++ Expressionでの陽解法のプログラミングです。 indows Visual C++ Expression2008が良くわからないのでコマンドプロンプトで実行しています。 熱方程式の初期値問題の陽解法のプログラムをなんとか組んでいます。 私が組んだプログラムではLinuxでは通るのですがwindows Visual C++ Expressionでは通りません。 このプログラムをwindows Visual C++ Expression 2008で通すにはどのように直したがいいのか教えて頂きたいと思います。よろしくお願いします。 以下は私なりに組んだプログラミングです。 πの値、u1[N+1]、u2[N+2] の3箇所でエラーがでてると思われます。 #include<stdio.h> #include<stdio.h> #include<math.h> int main(){ int i,k,kmax; int N=10; double dx double dt=0.01; double u1[N+1]; double u2[N+1]; double r=dt/(dx*dx); double T=1.0; kmax=T/dt; u1[0]=0; u1[N]=0; for(i=1;i<=N;i++){   u1[i]=sin(M_PI*i*dx); } for(k=1;k<=kmax;k++){ for(i=1;i<=N-1;i++){ u2[i]=r*u1[i-1]+(1-2*r)*u1[i]+r*u1[i+1]; }   for(i=1;i<=N-1;i++){ u1[i]=u2[i];   }   for(i=0;i<=N;i++){ printf("%f %f %f\n",dt*k,dx*i,u1[i]);   }   printf("\n"); } return 0; }

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

  • ベストアンサー
  • chie65535
  • ベストアンサー率43% (8526/19383)
回答No.4

>int N=10; >double u1[N+1]; >double u2[N+1]; 賢い最適化をするコンパイラなら、main関数の中でNが不変なので、Nを参照している部分を、定数の「10」に置き換えてしまうでしょう。 なので double u1[N+1]; double u2[N+1]; は double u1[10+1]; double u2[10+1]; としてコンパイルされ、コンパイルを通ってしまうでしょう。 ですが、そこまで賢くないコンパイラは「実行時変数は配列の要素数の指定に使えない」と怒るでしょう。 また、コンパイラによっては double u1[N+1]; double u2[N+1]; を double *u1,*u2; u1 = new double[N+1]; u2 = new double[N+1]; として動的に領域確保して、関数の出口で暗黙的なdeleteを行っているかも知れません。 いずれにせよ「異なる環境に移植すると、どうなるか判らない」のは間違いありません。 なお、math.hにM_PIが定義されてないコンパイル環境では #ifndef M_PI #define M_PI πの値を少なくとも15桁 #endif と書かねば、コンパイル出来ません。

exceland
質問者

お礼

皆様のおかげで無事に問題が解決できました。 その上問題の原因も理解することができ非常に助かりました。 慣れない質問の中、皆様優しく詳細に答えて頂き感謝いたします。

その他の回答 (4)

  • titokani
  • ベストアンサー率19% (341/1726)
回答No.5

M_PIですが、 #define _USE_MATH_DEFINES #include <math.h> とすれば、VisualC++でも使えるはずです。 Linuxで通って、VC++で通らないのは、C90とC99の違いでしょうね。 int N=10; を #define N 10 とすればよいのは、みなさんおっしゃる通りです。

exceland
質問者

お礼

これから多倍長計算でのプログラムに書き換えないといけなかったんで非常に助かります。 最後にこの私の質問を読んで考えていただいた皆様ありがとうございました。

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

gcc なら通りますよ>#2. そこに関してだけ言えば, 今の C の規格では OK. どちらにしても M_PI の手当は必要ですが.

exceland
質問者

お礼

コメントありがとうございます。

  • Tasuke22
  • ベストアンサー率33% (1799/5383)
回答No.2

Linuxで通るというのが信じがたいです。 結論を書けば下のように直せば通るでしょう。 ほかにもあるかもしれませんが、ここですね、まず。 int N=10;  ↓ #define N 10 解説。プログラムの値は、実行時のものと、コンパ イル時のものがあるということです。 int n=10; でNと表現したら、これは実行時に10に なりますが、コンパイル時は"N"なのです。 なので、コンパイル時に配列の定義をする場合、 double u1[N+1]; int Nの内容の10は得られない訳です。 従って、どんなOSでもCコンパイラではこれはエラー です。 #defineが数値に限らず、コンパイル時に指定された ものに置き換わります。

exceland
質問者

お礼

素早い返答ありがとうございます。 今までintとdefineの意味を考えずになんとなく使ってただけでしたが、違いがわかるようになりました。 お世話になりました。

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

・M_PI は普通定義されていないと思った方がいい. 代替手段が必要. ・配列の定義するときには大きさとして整定数しか使えないので int N=10; ではなく #define N 10 としなければならない. とりあえずこの辺.

exceland
質問者

お礼

素早くポイントを指摘していただいてありがとうございます。 お世話になりました。

関連するQ&A

  • Visual C++でのプログラミング

    学校でプログラミングの課題が出たので自分のパソコンに Microsoft Visual C++ 2010 Express をインストールして作ってみました。 それが以下のプログラムです。 これは任意の値nを入力してa[n]までの配列をつくり それを降順に並び替えるものです。 #include <stdio.h> #define N 10000 int main(){ int a[N],i,j,max,min,n,temp; n=0; printf("n="); scanf("%d",n); if(N<n){ return 0; } else if(n<=0){ return 0; } else if(n<=N){ for(i=0;i<=n;i++){ printf("a[%d]",i); scanf("%d\n",&a[i]); } max=min=a[0]; for(i=1;i<n;i++){ if(max<a[i]){ max=a[i]; } else if(min>a[i]){ min=a[i]; } } printf("a[i]のソート結果\n"); for(i=0;i<n;i++);{ for(j=i+1;j<n;j++){ if(a[i]<a[j]){ temp=a[i]; a[i]=a[j]; a[j]=temp; } } } for(i=0;i<n;i++){ printf("a[i]=%d\n",a[i]); } printf("Max=%d\n",max); printf("Min=%d\n",min); } } これをVisual C++でデバックすると 『test.exeの0x0fcbe42e(msvcr100d.dll)にハンドルされていない例外が発生しました:0C0000005: 場所 0x00000000 に書き込み中のアクセス違反が発生しました。』 と表示されて実行できません。 今日インストールしたばかりなのでどこでエラーが起きているのかわかりません。 これはプログラミングとVisual C++のどっちが原因なのでしょうか? もしお分かりになるならば、具体的な解決方法や プログラムの訂正点などを教えていただきたいです。

  • ファイルの読み込みが上手くいかず困っています。

    #include<stdio.h> #include<math.h> #include<time.h> #define i0 2 /*流体部分の最小格子番号*/ #define j0 2 #define k0 2 #define in 41 /*流体部分の最大格子番号*/ #define jn 41 #define kn 41 #define imax 44 /*境界を含めた格子の数*/ #define jmax 44 #define kmax 44 #define N 100000 void sabun(void); int i,j,k,n,pgosa,vgosa,x,y,z; double u[imax][jmax][kmax], v[imax][jmax][kmax], w[imax][jmax][kmax], p[imax][jmax][kmax]; double u2[imax][jmax][kmax], v2[imax][jmax][kmax], w2[imax][jmax][kmax], p2[imax][jmax][kmax]; double Vn=-1.0, a=10.0; /*初期値*/ double dt=0.001, dx=0.025, dy=0.025, dz=0.025, rei=250000.0; double dx2, dy2, dz2, po; main() { FILE *fpin,*fpout; clock_t start,end; start = clock(); /*時間計測開始*/ fpin=fopen("H-clock.dat", "r"); /*入力ファイル*/ if(fpin==NULL) { printf("入力ファイルのオープンに失敗しました"); return 0; } x=i-1; y=j-1; z=k-1; for(i=i0;i<=in+1;i++){ for(j=j0;j<jn+1;j++){ for(k=k0;k<kn+1;k++){ fscanf(fpin,"%d %d %d %.6lf %.6lf %.6lf %.6lf\n",&x,&y,&z,&u[i][j][k],&v[i][j][k],&w[i][j][k],&p[i][j][k]); printf("%d %d %d %.6lf %.6lf %.6lf %.6lf\n",x,y,z,u[i][j][k],v[i][j][k],w[i][j][k],p[i][j][k]); } } } 読み込みの部分のある部分まで載せているのですが読み込みの部分に問題が あると思うのですがどうすれば読み込んでくれるのか分かりません。ですので解決法を教えていただけると助かります、よろしくお願いします。

  • プログラミングのことで困っています。助けて下さい。

    プログラミングの問題がどうしても分からず、本当に困っています。 ・2x+y+3z=13 ・x+3y+2z=13 ・3x+2y+z=10 (解:x=1,y=2,z=3) を掃き出し法で解くプログラミングの問題で、次の(1)~(5)が何が当てはまるかどうしても分からないんです。 #include <stdio.h> #define N 3 /*未知数の個数*/ int main(void) { int i,j,k; double pivot,del; double a[N][n+1]={{2,1,3,13},{1,3,2,13},{3,2,1,10}}; /*係数行列*/ for(i=0;i<N;i++) { (1)____ /*ピボット係数*/ for(j=0;j<N+1;j++) /*ピボット行をピボットで割る*/ (2)____ for(k=0;k<N;k++) /*ピボット列の掃き出し*/ { if((3)____) { del=a[k][i]; for(j=i;j<N+1;j++) (4)____ } } } for(i=0;i<N;i++) (5)____ /*計算結果の表示*/ return 0; } 実行結果は x0=1.00 x1=2.00 x2=3.00 と表示させたいのですが、(1)~(5)の所がどうしても分からず、困っています。どなたか助けて下さい。お願いします。

  • C++ プログラミング

    連立方程式の逆行列と解を出そうとしたのですが /*n=4と定義nは元の数*/ #define n 4 int main() { /*係数マトリクスAと単位マトリクスと右辺ベクトルの定義*/ double a[n][n+5]={{4,1,3,2,1,0,0,0,23}, {1,4,3,3,0,1,0,0,30}, {5,5,10,5,0,0,1,0,65}, {4,4,2,6,0,0,0,1,42}}; double x,y; int i,j,k; /*#1ピボットの演算を行うためのループ*/ for(k=0;k<n;k++) { /*ピボット係数*/ x=a[k][k]; /*#2ピボットをにするための演算を行うためのループ*/ for(j=k;j<n+5;j++) /*ピボット行をxで割る*/ a[k][j]=a[k][j]/x; /*#3ピボット列の掃き出しを行うためのループ*/ for(i=0;i<n;i++) { /*#4iがkではないとき*/ if(i!=k) { y=a[i][k]; /*#5ピボット以外をにする演算を行うためのループ*/ for(j=k;j<n+5;j++) a[i][j]=a[i][j]-y*a[k][j]; } } } /*結果を表示*/ printf("係数マトリクスAの逆行列を表示\n"); for(i=0;i<n;i++){ for(j=4;j<n+4;j++){ printf("a[%d][%d]=%f",i+1,j-3,a[i][j]); } printf("\n"); } printf("連立方程式の解を表示\n"); for(i=0;i<n;i++) printf("x%d=%f\n",i+1,a[i][n+4]); return 0; このプログラムを打って 1>z:\win\personal\visual studio 2008\projects\課題2.cpp(35) : error C3861: 'printf': 識別子が見つかりませんでした 1>z:\win\personal\visual studio 2008\projects\課題2.cpp(38) : error C3861: 'printf': 識別子が見つかりませんでした 1>z:\win\personal\visual studio 2008\projects\課題2.cpp(40) : error C3861: 'printf': 識別子が見つかりませんでした 1>z:\win\personal\visual studio 2008\projects\課題2.cpp(42) : error C3861: 'printf': 識別子が見つかりませんでした 1>z:\win\personal\visual studio 2008\projects\課題2.cpp(44) : error C3861: 'printf': 識別子が見つかりませんでした 1>z:\win\personal\visual studio 2008\projects\課題2.cpp(46) : fatal error C1075: 左側 中かっこ '{' に対応するものが 'z:\win\personal\visual studio 2008\projects\課題2.cpp(4)' で見つかる前に EOF が検出されました。 とエラーがでました.printfはちゃんと定義されてると思うんですが何がおかしいのでしょうか・・・?

  • 偏微分方程式、差分法

    Fitzhugh-Nagumo方程式 dU/dt = d/dx(dU/dx) + (a-U)(U-1)U-V (d/dx(dU/dx)はUのxに対する二回微分) dV/dt =e(bU-gV) a=0.1, b=0.5, g=1.0, e=0.01 初期条件 (U,V)=(1,0) if x=0 (U,V)=(0,0) if x>0 境界条件 dU/dx=0 at x=0 dV/dx=0 at x=0 を差分して陽解法で解くと添付の答えになるらしいのですが、自分で解いたところ添付の結果のようになりました。答えと一致しないため、プログラム上で何を間違えているのかご指摘頂けると助かります。 #include <stdio.h> #include <stdlib.h> //exsit()で必要 #include <math.h> int main(){ double a,b,g,e; double dt,dx; int x,t; double **u,**v; int i,j,k; a=0.1;b=0.5;g=1.0;e=0.01; x=100;t=5000.; dt=0.001;dx=0.1; FILE *fp; if((fp = fopen("ResultNagumo.txt","w"))==NULL){ printf("Can't open file\n"); exit(2); } u = (double**)malloc(sizeof(double*)*t); v = (double**)malloc(sizeof(double*)*t); for(i=0;i<t;i++){ u[i]=(double*)malloc(sizeof(double)*x); v[i]=(double*)malloc(sizeof(double)*x); } //初期値 u[0][0]=1.0; v[0][0]=0.0; for(i=1;i<x;i++){ u[0][i]=0.0; v[0][i]=0.0; }    //差分計算 for(i=0;i<t-1;i++){ for(j=1;j<x-1;j++){ u[i+1][j] = u[i][j] + dt*((u[i][j+1]-2*u[i][j]+u[i][j-1])/pow(dx,2)+(a-u[i][j])*(u[i][j]-1)*u[i][j]-v[i][j]); v[i+1][j] = v[i][j] + dt*(e*(b*u[i][j]-g*v[i][j])); } //境界条件 u[i+1][0]=u[i+1][1]; v[i+1][0]=v[i+1][1]; u[i+1][x-1]=u[i+1][x-2]; v[i+1][x-1]=v[i+1][x-2]; }   //結果の出力 for(i=0;i<t;i++){ if((i%100)==0){ fprintf(fp,"%d\n",i); for(j=0;j<x;j++){ fprintf(fp,"%2.4e,",u[i][j]); } } } for(i=0;i<t;i++){ free(u[i]); free(v[i]); } free(u);free(v); fclose(fp); getchar(); return 0; }

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

    /*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の引数にポインタがついているのはなぜか,またポインタを使用しない方法はないか?また、オイラー法より精度の高い解法はありますか? よろしくお願いします。

  • C言語の配列の宣言について

    20年以上前に発行された本に書いてある、利用したいCのコードがあります。 JavaやPHPは使ったことがありますが、Cは触ったことすらありません。 とりあえずメモ帳に打ち出して、codepadでC codeで実行してみましたが、正常に動作しません。 どこがおかしいのか、ご教示ください。 よろしくお願いします。 ---- #include <stdio.h> #include <math.h> #define N 20; int main( int argc, char **argv ) { double u[N+1], w[N+1]; double k=0.001; double h, r, s; int i, j; h= 1.0/(double)N; r= k/(h*h); s= 1.0-2.0*r; for( i=0; i<=N; i++ ) w[i]=0.0; for( i=1; i<N; i++ ) u[i]=1.0; u[0]=0.0; u[N]=0.0; for(j=1;j<200;j++){ if((j%10)==0) { printf("%5.31f",(double)j*k); for(i=0;i<=N;i+=2) printf("%5.31f",u[i]); printf("\n"); } for( i=0; i<=w; i++ ) w[i]=r*(u[i+1]+u[i-1])+s*u[i]; for( i=1; i<N; i++ ) u[i]=w[i]; } return 0; }

  • C++言語のプログラムをfortranに変換

    const int N = 100; const double q = 10.0, dt = 0.00001, Dm = 30.0, t0 = 2.0, K = 1.0, pi = 3.141592, f = 3.0; double C[N], dC[N]; double dx = q/N; for (int i = 0; i < N; ++i) C[i] = 0; // 初期条件 for (double t = 0; t < t0; t += dt) {  C[0] = 0; // 境界条件1  C[N - 1] = K*sin(2*pi*f*t); // 境界条件2  for (int i = 1; i < N - 1; ++i) dC[i] = (Dm*(C[i + 1] - 2*C[i] + C[i - 1])/(dx*dx))*dt;  for (int i = 1; i < N - 1; ++i) C[i] += dC[i]; } for (int i = 0; i < N; ++i) cout << C[i] << endl; // t = t0 このプログラムをfortranに変換できる方いますか?

  • プログラミングで・・・

    以下のプログラムにおいて,N回 s=--- s=---  ・  ・  ・ と表示させるにはどうしたらよいでしょか. ----------------------------------------- /*台形公式*/ #include<stdio.h> #include<math.h> double f(double x); int main(void){ /*Define variablest*/ int i,N; double a,b; double dx,xi,s,err; /*Function*/ printf("f=sin(x)+1/2cos10x\n"); /*Integral Field*/ a=0; b=M_PI; printf("a=0\n"); printf("b=pai\n"); /*Inputs data*/ printf("N="); scanf("%d",&N); /*width of integral's range*/ dx=(b-a)/(double)N; s=f(a)*0.5; /*for Loop*/ s=0; for(i=1;i<=N; i++){ xi=a+dx*(double)i; s=s+f(xi); } s=s+f(b)*0.5; s=s*dx; printf("s=%6.3e err=%6.3e\n",s,err); return 0; } double f(double x){ return sin(x)+1/2*cos(10*x); }

  • プログラミングの課題で困ってます。

    正弦関数x=sintのグラフを■で描きなさい(31行程度で)。数値xに対する■の数はウインド各行に表示される しきれる範囲内で任意に定めてよい。 という課題が出ました。よくわからなくて困っています。 下記に書いてるプログラミングを参考に答えを教えていただきたいと思い、質問させていただきました。よろしくお願いします。 また、下記を参考にしなくてもよいです。 プログラミングはvisual C++ 2008を使ってます。 #include "stdafx.h" #include<stdio.h> #include<math.h> int _tmain(int argc, _TCHAR* argv[]) { double x[100]; int i , j; for(i=0; i<31; i++){ x[i]=sin(0.1*i); } // for(j=0; j<31; j++){ // printf("%lf\n",y[j]); // } for(i=0; i<31; i++){ for(j=0; j<x[i]*20; j++){ printf("■"); } printf("\n"); } return 0; }