C言語関係掲示板

過去ログ

No.1016 微分方程式(陰関数)

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

微分方程式(陰関数)
投稿者---ゆっこ(2004/02/07 01:06:04)


y’+1/√{(y')^2+0.1}=x/y
の解(0≦x≦2)を図示して求めなさい。
ただし、初期値はy(0)=1

こういった問題をC言語で解く場合どうやってプログラムするのですか?
教えてください。

No.1272

Re:微分方程式(陰関数)
投稿者---たか(2004/02/07 18:29:40)


>y’+1/√{(y')^2+0.1}=x/y
>の解(0≦x≦2)を図示して求めなさい。
>ただし、初期値はy(0)=1
>
>こういった問題をC言語で解く場合どうやってプログラムするのですか?
>教えてください。

オイラー法やルンゲ・クッタ法等の解法を使用するには、まず正規形に
直す必要があります。

y'=f(x,y)のように、まずy'について解きます。今回の場合はy'が2乗
されていますので、±の両方の場合について解く必要があるでしょう。
後はオイラー法などを調べて(ネットにたくさんあります)、それで
解いてみて下さい。今回は丸投げという事で、プログラムは無しです。

No.1273

Re:微分方程式(陰関数)
投稿者---ゆっこ(2004/02/07 20:50:28)


とけました。たかさんありがとうございます。
続いて新たな課題が出たんですけど。。。
y'={e^(0.01/(x-0.5)^2+0.002)}+5e^y
y(0)=0
を解くために
y'=f(x,y)
に対して
{y(x+h)-y(x)}/h=f(x,y)+f{x+h,y(x+h)}/2のように近似してニュートン法で解くときx-y平面上で解(0≦x≦1)を図示しなさい。。
#include <stdio.h>
#include <math.h>
#include "chinougl.h"
#define x0 2.5
#define nmax 20
#define e 0.0025
#define USE userf2
//#define DBG

typedef struct{
double fnc;
double dfn;
} FV;
typedef struct{
double x;
int n;
} RS;

FV userf1(double);
FV userf2(double);
RS newt(FV (*)());

#ifdef DBG
void gr(FV (*)());
#endif

int main(){
RS res;
res=newt(USE);
printf("\n answer n=%d x=%f\n\n",res.n,res.x);
return 0;
}

RS newt(FV (*fn)()){
int n=0;
double x=x0,er;
RS res;
FV func;


do {
func=fn(x);
er=func.fnc/func.dfn;
x=x-er;
n++;
printf("%d %10.7f %10.7f\n",n,x,er);
} while(fabs(er)>e && n<nmax);
res.n=n;
res.x=x;
#ifdef DBG
gr(fn);
#endif
return res;
}

FV userf1(double x){
FV fun;
fun.fnc=pow(x,3)-1.0;
fun.dfn=3.0*pow(x,2);
return fun;
}

FV userf2(double x){
FV fun;
fun.fnc=pow(x,3)+2.0*pow(x,2)-5.0*x+6.0;
fun.dfn=3.0*pow(x,2)+4.0*x-5.0;
return fun;
}


#ifdef DBG
void gr(FV (*fn)()){
int n=0;
double x;
line(-1,0,1,0);color(1,1,1);
line(0,-1,0,1);color(1,1,1);
for(x=-5.0;x<=5.0;x+=0.1){
if ((n%10)==0){
line(x/5.0,0.0,x/5.0,0.1);color(1,1,1);
}
n++;
line(x/5,fn(x).fnc/20.0,(x+0.1)/5.0,fn(x+0.1).fnc/20.0);color(1,1,0);
}
gotogl();
}
#endif

ニュートン法は作りました。







No.1274

Re:微分方程式(陰関数)
投稿者---たか(2004/02/07 21:53:19)


>y'={e^(0.01/(x-0.5)^2+0.002)}+5e^y
>y(0)=0
>を解くために
>y'=f(x,y)
>に対して
>{y(x+h)-y(x)}/h=f(x,y)+f{x+h,y(x+h)}/2のように近似してニュートン法で解くときx-y平面上で解(0≦x≦1)を図示しなさい。。

(途中略)

>ニュートン法は作りました。

これなんですけど、ニュートン法はx=0となる点を求める事です。微分
方程式の解とは普通x=0となる点を求める事ではなく、一般解を求める
事なしに数値解だけを得る事を意味します。ですから求めようとする物
が全く違います。

本当にこの文の通りの問題でしたでしょうか?

No.1276

Re:微分方程式(陰関数)
投稿者---ゆっこ(2004/02/08 00:22:39)


はい。
この問題通りです。グラフィク使って解を図示する事が目的です。
一般解を求めたりする必要はありません。

No.1290

誰かお願いします。
投稿者---ゆっこ(2004/02/09 04:12:27)


まだ、できあがってません。ヒントでも何でもいいんで教えてください。
お願いします。

No.1293

Re:微分方程式(陰関数)追加
投稿者---たか(2004/02/09 15:40:34)


一つ質問していいでしょうか。

(y(x+h)-y(x))/h = f(x,y) + f(x+h, y(x+h))/2
についてなんですけど、漸化式風にy(x+h)を求める際に右辺で既にy(x+h)
が必要になります。このままではニュートン法では解けません。しかも
y(x+h)がf()の中に入っているので、y(x+h)について解く事もできません。

こういう場合先生は授業中どうすればいいとおっしゃっておられましたか?
それが分かればプログラムが書けるのですけど。
私が知っているのは右辺がxのみで出来ている場合だけです。

No.1294

Re:微分方程式(陰関数)問題記入ミス
投稿者---ゆっこ(2004/02/09 16:48:12)


実は授業中にやってないんです。だから、詳しくは説明できません。
一つ問題に記入ミスがありました。
>(y(x+h)-y(x))/h = f(x,y) + f(x+h, y(x+h))/2
            ↓
(y(x+h)-y(x))/h = {f(x,y) + f(x+h, y(x+h))}/2
この、近似ならどうでしょうか??

<問題訂正(完全版>
y'={e^(0.01/(x-0.5)^2+0.002)}+5e^y
y(0)=0を解くために
y'=f(x,y)に対して
{y(x+h)-y(x)}/h=f(x,y)+f{x+h,y(x+h)}/2のように近似して
ニュートン法で解くときx-y平面上で解(0≦x≦1)を図示しなさい。。
ただし、刻み幅hとしh=1/30とする。



 

No.1295

Re:微分方程式(陰関数)問題記入ミス
投稿者---たか(2004/02/09 17:06:47)


>>(y(x+h)-y(x))/h = f(x,y) + f(x+h, y(x+h))/2
>            ↓
>(y(x+h)-y(x))/h = {f(x,y) + f(x+h, y(x+h))}/2

つまり、dy/dx = (y(x+h) - y(x))/h と近似する事ですよね。そして、
y(x+h) を次々と求めていく事がこの問題の解になります。(xは0〜1)
ところが、右辺にも自分自身 y(x+h) が現れているので、このままでは
解けないのです。何とか右辺の y(x+h) を消去したいのですが、f()の
中に入ってしまっているのでおいそれとは消去できません。

授業中にやってない問題を出すとは先生も意地悪ですね。

No.1297

それともう一つ
投稿者---たか(2004/02/09 17:12:39)


これらの問題は、手書きでグラフを描き提出せよ、と書いてあったので
しょうか。それとも、C言語で(x、y)を求め、画面に描画せよ、と書いて
あったのでしょうか。

もしC言語で描画するのであれば、y'について解きにくい問題を出すとは
思えないのです。それが私の疑問点です。

No.1298

Re:それともう一つ
投稿者---ゆっこ(2004/02/09 17:42:53)


>これらの問題は、手書きでグラフを描き提出せよ、と書いてあったので
>しょうか。それとも、C言語で(x、y)を求め、画面に描画せよ、と書いて
>あったのでしょうか。
C言語で描画しなければなりません。描写が目的です。
y(x,y)に関しては、多分消去ではなく。近似式をOOO=0と言う形にして
微分方程式をOOO=0に入れ、ニートンで解けるようになる。のが手順だと思うのですが…
なんか質問に答えられていないようですが…

No.1299

Re:それともう一つ
投稿者---たか(2004/02/09 17:57:30)


>C言語で描画しなければなりません。描写が目的です。
>y(x,y)に関しては、多分消去ではなく。近似式をOOO=0と言う形にして
>微分方程式をOOO=0に入れ、ニートンで解けるようになる。のが手順だと思うのですが…
>なんか質問に答えられていないようですが…

ちなみに、ニュートン法でなくて微分方程式を解くのによく使われる
オイラー法のプログラムを置いておきます。yがいきなり発散し、グラフ
が書けそうにありません。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define DIVN 1000
#define M 1
#define DX 30

void euler(double [], double [][M], double, int, int);
void euler_sub(double, double [], double []);

int main(void)
{
  double h, x[DIVN], y[DIVN][M];
  int i, n;

  printf("\n** y' - {e^(0.01/(x-0.5)^2+0.002)}+5e^y = 0 **\n");
  x[0] = y[0][0] = 0; n = DX; h = 1. / DX;
  printf("X の初期値 X0 = %f\n", x[0]);
  printf("Y の初期値 Y0 = %f\n", y[0][0]);
  printf("刻み値 N = %d\n", n);
  printf("進み幅 H = %f\n", h);

  euler(x, y, h, n, M);
  printf("\%15s%15s\n\n","X","Y");
  for (i = 0; i <= n; i++)
    printf("%17.8e%17.8e\n", x[i], y[i][0]);

  return 0;
}

/*
 * オイラー法
 */
void euler(double x[], double y[][M], double h, int n, int m)
{
  int i, k;
  double f[DIVN];
  
  for (k = 0; k <= n; k++) {
    x[k] = x[0] + k * h;
    euler_sub(x[k], y[k], f);
    for (i = 0; i < m; i++)
      y[k + 1][i] = y[k][i] + h * f[i];
  }
}

void euler_sub(double x, double y[], double f[])
{
  f[0] = exp(0.01 / pow(x - 0.5, 2) + 0.002) + 5 * exp(y[0]);
}


No.1300

Re:それともう一つ
投稿者---ゆっこ(2004/02/09 22:15:29)


近似式とニュートン法使えばグラフが書けると聞いてますが…


No.1301

Re:それともう一つ
投稿者---たか(2004/02/09 22:18:57)


>近似式とニュートン法使えばグラフが書けると聞いてますが…

私にはわからないので他の方の解答を待ちましょう。

No.1303

Re:それともう一つ
投稿者---pipi(2004/02/10 19:46:14)


y'=e^{0.01/(x-0.5)^2 + 0.002} + 5e^{y(x)}                  -(1)
初期条件 y(0)=0                                            -(2)
近似式   (y(x+h)-y(x)) / h = {f(x,y) + f(x+h, y(x+h))}/2 -(3)
刻み幅 h=1/30

(1)(3)において
y(x)           を y(n)    
y(x+h)         を y(n+1) 
f(x, y)        を f(n) 
f(x+h, y(x+h)) を f(n+1)   (n = 0,1,2 ...)
と置き換えると

y'(n) = f(n) = e^{0.01/(x(n)-0.5)^2 + 0.002}  +  5e^{y(n)} -(4)
(y(n+1) - y(n)) / h = (f(n) + f(n+1)) / 2  (h=x(n+1)-x(n)) -(5)
となる

(5)の近似式を(4)に適用すると
(y(n+1) - y(n)) / h =  (e^{0.01/(x(n)-0.5)^2 + 0.002} + 5e^{y(n)}
                        + e^{0.01/(x(n+1)-0.5)^2 + 0.002}  +  5e^{y(n+1)}) / 2  -(6)
となる

(6)を変型すると
0 = y(n+1)
    - y(n)
    - h/2( e^{0.01/(x(n)-0.5)^2   + 0.002}  
           +  5e^{y(n)} 
           + e^{0.01/(x(n+1)-0.5)^2 + 0.002} ) 
    - h/2 * 5e^{y(n+1)}
   = z(y(n+1))     -(7)
となる

x(n), y(n), h, x(n+1)=x(n)+h の値がわかっていれば
z(y(n+1)) = 0 を y(n+1) について解くことができる(ニュートン法を使う)

n = 0 のとき
x(n) = x(0) = 0
y(n) = y(0) = 0
h = 1/30
x(n+1) = x(1) = x(0) + h = h
これらの値を(7)に代入して x(1)=0+h のときの y(1) の値を求める

n = 1 のときも同様の操作を繰り返す


これで出来ないでしょうか?


No.1312

見てください
投稿者---ゆっこ(2004/02/14 12:27:22)


プログラム作りましたが、これではうまくグラフが描けませんでした。
つまり、刻み幅が30で書くために、私はグラフを陽側から推測してニュートン法で解きました。が、先生は陰側からグラフを推測すれば刻み幅が30でも滑らかな曲線が描けるそうです。しかし、陰側からの推測して解くプログラムが分りません。分る方教えてください。また、このプログラムで間違いがあれば指摘の方もお願いします。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "chinougl.h"
#define EXP 2.718281828
#define SC 0.8

void mdeul(int n, double x0, double y0, double xn);
void gr(int i, double x, double y);
typedef struct{
    double fnc;
    double dfn;
}FV;

double c=1.0;
int main(){
int i,n=30;
double x0=0.0,y0=0.0,xn=1.0;
mdeul(n, x0, y0, xn);c++;
//for(i=0;i<n;n++){x[i]=x0;y[i]=y0;}
gotogl();
return 0;
}

FV fn(double x, double y, double z){
    FV ff;
    ff.fnc=z-pow(EXP,0.01/(pow(x-0.5,2)+0.002))+5.0*pow(EXP,y);
    ff.dfn=1;
    return ff;
}

double F(double x, double y){
    int n=0,nmax=30;
    double er,e=1.0e-6;
    static double z=0.0;
    static int k=0;
    FV func;
    do {
        func=fn(x,y,z);
        er=func.fnc/func.dfn;
        z=z-er;
        n++;
    }while(fabs(er)>e && n<nmax);
    if(n==nmax)
    gotogl();
k++;
return z;
}


void mdeul(int n, double x0, double y0, double xn){
        int i;
        double x,xp,y,yp,h;
x=x0;
y=y0;
h = (xn - x0) / n;
for(i=0;i<n;i++){
    yp = y + F(x, y) * h;
    xp = x + h;
    y += (h / 2) * (F(x, y) + F(xp, yp));
    x += h;
    gr(i,x*SC,y*SC);
  }
    return;
}

void gr(int i, double x, double y){

static double xo,yo;

if (i){
      line(xo/2-1*SC,yo/2*SC,x/2-1*SC,y/2*SC);
      switch((int)c){
   case 1: color(0,0,1);break;
   case 2: color(1,0,0);break;
   case 3: color(0,1,0);break;
   case 4: color(1,1,1);
   }
   }

xo=x;
yo=y;


No.1313

Re:見てください
投稿者---pipi(2004/02/15 18:13:39)


>プログラム作りましたが、これではうまくグラフが描けませんでした。
>つまり、刻み幅が30で書くために、私はグラフを陽側から推測してニュートン法で解きました。

刻み幅は 1/30 ではなかったのですか。

近似式 (y(x+h)-y(x)) / h = {f(x,y) + f(x+h, y(x+h))}/2
を使う解法は台形法と呼ばれるものだと思われます。

台形法は台形公式を使うことからそう呼ばれます。台形公式を以下に示します。

y(xn+1) = y(xn) + h/2[f(xn, y(xn)) + f(xn+1,y(xn+1))]

今、左辺の値 y(xn+1) を求めたいとします。この式の右辺を見ると、
まだ計算されていない y(xn+1) が含まれているので、このままでは
計算出来ません。そのため、式を y(xn+1) について解く必要があります。
このように左辺の値 y(xn+1) をもとめようとするにもかかわらず、
この y(xn+1) が右辺にも出て来るような公式を陰的公式(implicit formula)
といいます。また、陰的公式を使う台形法を陰的な解法といいます。

逆に、オイラー法やルンゲ-タック法を陽的な解法といいます。


"微分方程式 台形法"などのキーワードで検索すると、かなりの情報が得られると思います。

No.1314

Re:見てください
投稿者---ゆっこ(2004/02/16 07:39:00)


刻み幅は1/30ですすみません。


No.1319

Re:見てください
投稿者---ゆっこ(2004/02/17 11:25:58)


まだ、いまいちわかりません。
もう少し、ヒントをお願いします。