| 情報学部 | 菅沼ホーム | 目次 | 索引 |
/**********************************/
/* 微分方程式(ルンゲ・クッタ法) */
/* 例:d2x/dt+3dx/dt+2x=1 */
/* coded by Y.Suganuma */
/**********************************/
#include <stdio.h>
void snx(double, double *, double *);
double rkg(double, double, double *, double *, double **, int,
void (*)(double, double *, double *));
int main()
{
double time, h, *x, *dx, **g;
int i1, n = 2;
/*
初期設定
*/
x = new double [n];
dx = new double [n];
g = new double * [4];
for (i1 = 0; i1 < 4; i1++)
g[i1] = new double [n];
time = 0.0;
h = 0.01;
x[0] = 0.0;
x[1] = 0.0;
/*
計算と出力
*/
for (i1 = 0; i1 < 101; i1++) {
printf("time = %f, x = %f\n", time, x[0]);
time = rkg(time, h, x, dx, g, n, snx);
}
return 0;
}
/****************/
/* 微係数の計算 */
/****************/
void snx(double time, double *x, double *dx)
{
dx[0] = x[1];
dx[1] = -2.0 * x[0] - 3.0 * x[1] + 1.0;
}
/*******************************************/
/* ルンゲ・クッタ法 dx/dt=f(t,x) */
/* time : 現在の時間 */
/* h : 時間刻み幅 */
/* x : 現在の状態 */
/* dx : 微係数(f(t,x):snxで計算する)*/
/* g : 作業域(g[4][n]) */
/* n : 微分方程式の次数 */
/* sub : 微係数を計算する関数の名前 */
/* return : time+h */
/*******************************************/
double rkg(double time, double h, double *x, double *dx, double **g,
int n, void (*sub)(double, double *, double *))
{
int i1;
double h2;
h2 = 0.5 * h;
(*sub)(time, x, dx);
for (i1 = 0; i1 < n; i1++)
g[0][i1] = h * dx[i1];
time += h2;
for (i1 = 0; i1 < n; i1++)
g[1][i1] = x[i1] + 0.5 * g[0][i1];
(*sub)(time, g[1], dx);
for (i1 = 0; i1 < n; i1++)
g[1][i1] = h * dx[i1];
for (i1 = 0; i1 < n; i1++)
g[2][i1] = x[i1] + 0.5 * g[1][i1];
(*sub)(time, g[2], dx);
for (i1 = 0; i1 < n; i1++)
g[2][i1] = h * dx[i1];
time += h2;
for (i1 = 0; i1 < n; i1++)
g[3][i1] = x[i1] + g[2][i1];
(*sub)(time, g[3], dx);
for (i1 = 0; i1 < n; i1++)
g[3][i1] = h * dx[i1];
for (i1 = 0; i1 < n; i1++)
x[i1] = x[i1] + (g[0][i1] + 2.0 * g[1][i1] + 2.0 * g[2][i1] + g[3][i1]) / 6.0;
return time;
}
/**********************************/
/* 微分方程式(ルンゲ・クッタ法) */
/* 例:d2x/dt+3dx/dt+2x=1 */
/* coded by Y.Suganuma */
/**********************************/
import java.io.*;
public class Test {
public static void main(String args[]) throws IOException
{
double time, h, x[], dx[], g[][];
int i1, n = 2;
/*
初期設定
*/
x = new double [n];
dx = new double [n];
g = new double [4][n];
time = 0.0;
h = 0.01;
x[0] = 0.0;
x[1] = 0.0;
/*
計算と出力
*/
Kansu kn = new Kansu();
for (i1 = 0; i1 < 101; i1++) {
System.out.println("time = " + time + " x = " + x[0]);
time = kn.rkg(time, h, x, dx, g, n);
}
}
}
/****************/
/* 微係数の計算 */
/****************/
class Kansu extends RKG
{
void snx(double time, double x[], double dx[])
{
dx[0] = x[1];
dx[1] = -2.0 * x[0] - 3.0 * x[1] + 1.0;
}
}
abstract class RKG
{
/*************************************************/
/* ルンゲ・クッタ法 dx/dt=f(t,x) */
/* time : 現在の時間 */
/* h : 時間刻み幅 */
/* x : 現在の状態 */
/* dx : 微係数(f(t,x):snxで計算する) */
/* g : 作業域(g[4][n]) */
/* n : 微分方程式の次数 */
/* return : time+h */
/*************************************************/
abstract void snx(double time, double x[], double dx[]);
double rkg(double time, double h, double x[], double dx[], double g[][], int n)
{
int i1;
double h2;
h2 = 0.5 * h;
snx(time, x, dx);
for (i1 = 0; i1 < n; i1++)
g[0][i1] = h * dx[i1];
time += h2;
for (i1 = 0; i1 < n; i1++)
g[1][i1] = x[i1] + 0.5 * g[0][i1];
snx(time, g[1], dx);
for (i1 = 0; i1 < n; i1++)
g[1][i1] = h * dx[i1];
for (i1 = 0; i1 < n; i1++)
g[2][i1] = x[i1] + 0.5 * g[1][i1];
snx(time, g[2], dx);
for (i1 = 0; i1 < n; i1++)
g[2][i1] = h * dx[i1];
time += h2;
for (i1 = 0; i1 < n; i1++)
g[3][i1] = x[i1] + g[2][i1];
snx(time, g[3], dx);
for (i1 = 0; i1 < n; i1++)
g[3][i1] = h * dx[i1];
for (i1 = 0; i1 < n; i1++)
x[i1] = x[i1] + (g[0][i1] + 2.0 * g[1][i1] + 2.0 * g[2][i1] + g[3][i1]) / 6.0;
return time;
}
}
<!DOCTYPE HTML>
<HTML>
<HEAD>
<TITLE>微分方程式(ルンゲ・クッタ)</TITLE>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
<SCRIPT TYPE="text/javascript">
eq = new Array();
function main()
{
// データの設定
let n = parseInt(document.getElementById("order").value);
let t1 = parseFloat(document.getElementById("t1").value);
let t2 = parseFloat(document.getElementById("t2").value);
let h = parseFloat(document.getElementById("haba").value);
let x = new Array();
x = document.getElementById("ini").value.split(/ {1,}/)
for (let i1 = 0; i1 < n; i1++)
x[i1] = parseFloat(x[i1]);
eq = document.getElementById("func").value.split(/\n{1,}/)
for (let i1 = 0; i1 < n; i1++)
eq[i1] = eq[i1] + ";";
dx = new Array();
g = new Array();
for (let i1 = 0; i1 < 4; i1++)
g[i1] = new Array();
// 実行,結果
let time = t1;
let c = 100000;
let str = "";
while (time < t2+0.1*h) {
let s1 = Math.round(time * c) / c;
str = str + "time = " + s1 + " x =";
for (let i1 = 0; i1 < n; i1++) {
let s2 = Math.round(x[i1] * c) / c;
str = str + " " + s2;
}
str += "\n";
time = rkg(time, h, x, dx, g, n, snx);
}
document.getElementById("res").value = str;
}
/****************/
/* 関数値の計算 */
/****************/
function snx(n, x, dx)
{
for (let i1 = 0; i1 < n; i1++)
dx[i1] = eval(eq[i1]);
}
/********************************************/
/* ルンゲ・クッタ法 dx/dt=f(t,x) */
/* time : 現在の時間 */
/* h : 時間刻み幅 */
/* x : 現在の状態 */
/* dx : 微係数(f(t,x):snxで計算する) */
/* g : 作業域(g[4][n]) */
/* n : 微分方程式の次数 */
/* fn : 関数値を計算する関数 */
/* return : time+h */
/********************************************/
function rkg(time, h, x, dx, g, n, fn)
{
let h2 = 0.5 * h;
fn(n, x, dx);
for (let i1 = 0; i1 < n; i1++)
g[0][i1] = h * dx[i1];
time += h2;
for (let i1 = 0; i1 < n; i1++)
g[1][i1] = x[i1] + 0.5 * g[0][i1];
fn(n, g[1], dx);
for (let i1 = 0; i1 < n; i1++)
g[1][i1] = h * dx[i1];
for (let i1 = 0; i1 < n; i1++)
g[2][i1] = x[i1] + 0.5 * g[1][i1];
fn(n, g[2], dx);
for (let i1 = 0; i1 < n; i1++)
g[2][i1] = h * dx[i1];
time += h2;
for (let i1 = 0; i1 < n; i1++)
g[3][i1] = x[i1] + g[2][i1];
fn(n, g[3], dx);
for (let i1 = 0; i1 < n; i1++)
g[3][i1] = h * dx[i1];
for (let i1 = 0; i1 < n; i1++)
x[i1] = x[i1] + (g[0][i1] + 2.0 * g[1][i1] + 2.0 * g[2][i1] + g[3][i1]) / 6.0;
return time;
}
</SCRIPT>
</HEAD>
<BODY STYLE="font-size: 130%; background-color: #eeffee;">
<H2 STYLE="text-align:center"><B>微分方程式(ルンゲ・クッタ)</B></H2>
<DL>
<DT> テキストフィールド及びテキストエリアには,例として,微分方程式,
<P STYLE="text-align:center"><IMG SRC="rkg.gif"></P>
<DT>を解く場合に対する値が設定されています(他の問題を実行する場合は,それらを適切に修正してください).ルンゲ・クッタ法を使用するためには,1 次の連立微分方程式に変換する必要があるため,
<P STYLE="text-align:center"><IMG SRC="rkg1.gif"></P>
<DT>とおき,以下に示すような 1 次の連立微分方程式に変換しています.
<P STYLE="text-align:center"><IMG SRC="rkg2.gif"></P>
<DT>テキストエリアに設定してあるのは,これらの式の右辺です.ただし,変数 x<SUB>1</SUB> や x<SUB>2</SUB> の代わりに,配列の要素 x[0] と x[1] を使用しています.なお,式は,JavaScript の仕様に適合した形式で記述してあることに注意してください.
</DL>
<DIV STYLE="text-align:center">
次数(n):<INPUT ID="order" STYLE="font-size: 100%" TYPE="text" SIZE="2" VALUE="2">
範囲:<INPUT ID="t1" STYLE="font-size: 100%" TYPE="text" SIZE="3" VALUE="0.0">,
<INPUT ID="t2" STYLE="font-size: 100%" TYPE="text" SIZE="3" VALUE="1.0">
幅:<INPUT ID="haba" STYLE="font-size: 100%" TYPE="text" SIZE="3" VALUE="0.01">
初期値(n個):<INPUT ID="ini" STYLE="font-size: 100%" TYPE="text" SIZE="10" VALUE="0.0 0.0"><BR><BR>
微分方程式 <BUTTON STYLE="font-size: 100%; background-color: pink" onClick="main()">実行</BUTTON><BR>
dx = <TEXTAREA ID="func" STYLE="font-size: 110%" COLS="70" ROWS="10">
x[1]
-2.0 * x[0] - 3.0 * x[1] + 1.0
</TEXTAREA><BR><BR>
結果<BR>
<TEXTAREA ID="res" STYLE="font-size: 110%" COLS="50" ROWS="10"></TEXTAREA>
</DIV>
</BODY>
</HTML>
<?php
/*
初期設定
*/
$n = 2;
$x = array($n);
$dx = array($n);
$g = array(4);
for ($i1 = 0; $i1 < 4; $i1++)
$g[$i1] = array($n);
$time = 0.0;
$h = 0.01;
$x[0] = 0.0;
$x[1] = 0.0;
/*
計算と出力
*/
for ($i1 = 0; $i1 < 101; $i1++) {
printf("time = %f, x = %f\n", $time, $x[0]);
$time = rkg($time, $h, $x, $dx, $g, $n, "snx");
}
/****************/
/* 微係数の計算 */
/****************/
function snx($time, $x, &$dx)
{
$dx[0] = $x[1];
$dx[1] = -2.0 * $x[0] - 3.0 * $x[1] + 1.0;
}
/*******************************************/
/* ルンゲ・クッタ法 dx/dt=f(t,x) */
/* time : 現在の時間 */
/* h : 時間刻み幅 */
/* x : 現在の状態 */
/* dx : 微係数(f(t,x):snxで計算する)*/
/* g : 作業域(g[4][n]) */
/* n : 微分方程式の次数 */
/* sub : 微係数を計算する関数の名前 */
/* return : time+h */
/*******************************************/
function rkg($time, $h, &$x, $dx, $g, $n, $sub)
{
$h2 = 0.5 * $h;
$sub($time, $x, $dx);
for ($i1 = 0; $i1 < $n; $i1++)
$g[0][$i1] = $h * $dx[$i1];
$time += $h2;
for ($i1 = 0; $i1 < $n; $i1++)
$g[1][$i1] = $x[$i1] + 0.5 * $g[0][$i1];
$sub($time, $g[1], $dx);
for ($i1 = 0; $i1 < $n; $i1++)
$g[1][$i1] = $h * $dx[$i1];
for ($i1 = 0; $i1 < $n; $i1++)
$g[2][$i1] = $x[$i1] + 0.5 * $g[1][$i1];
$sub($time, $g[2], $dx);
for ($i1 = 0; $i1 < $n; $i1++)
$g[2][$i1] = $h * $dx[$i1];
$time += $h2;
for ($i1 = 0; $i1 < $n; $i1++)
$g[3][$i1] = $x[$i1] + $g[2][$i1];
$sub($time, $g[3], $dx);
for ($i1 = 0; $i1 < $n; $i1++)
$g[3][$i1] = $h * $dx[$i1];
for ($i1 = 0; $i1 < $n; $i1++)
$x[$i1] = $x[$i1] + ($g[0][$i1] + 2.0 * $g[1][$i1] + 2.0 * $g[2][$i1] + $g[3][$i1]) / 6.0;
return $time;
}
?>
#*********************************/
# 微分方程式(ルンゲ・クッタ法) */
# 例:d2x/dt+3dx/dt+2x=1 */
# coded by Y.Suganuma */
#*********************************/
#***************/
# 微係数の計算 */
#***************/
snx = Proc.new { |time, x, dx|
dx[0] = x[1]
dx[1] = -2.0 * x[0] - 3.0 * x[1] + 1.0
}
#******************************************/
# ルンゲ・クッタ法 dx/dt=f(t,x) */
# time : 現在の時間 */
# h : 時間刻み幅 */
# x : 現在の状態 */
# dx : 微係数(f(t,x):snxで計算する)*/
# g : 作業域(g[4][n]) */
# n : 微分方程式の次数 */
# snx : 微係数を計算する関数の名前 */
# return : time+h */
#******************************************/
def rkg(time, h, x, dx, g, n, &sub)
h2 = 0.5 * h
sub.call(time, x, dx)
for i1 in 0 ... n
g[0][i1] = h * dx[i1]
end
time += h2
for i1 in 0 ... n
g[1][i1] = x[i1] + 0.5 * g[0][i1]
end
sub.call(time, g[1], dx)
for i1 in 0 ... n
g[1][i1] = h * dx[i1]
end
for i1 in 0 ... n
g[2][i1] = x[i1] + 0.5 * g[1][i1]
end
sub.call(time, g[2], dx)
for i1 in 0 ... n
g[2][i1] = h * dx[i1]
end
time += h2
for i1 in 0 ... n
g[3][i1] = x[i1] + g[2][i1]
end
sub.call(time, g[3], dx)
for i1 in 0 ... n
g[3][i1] = h * dx[i1]
end
for i1 in 0 ... n
x[i1] = x[i1] + (g[0][i1] + 2.0 * g[1][i1] + 2.0 * g[2][i1] + g[3][i1]) / 6.0
end
return time
end
# 初期設定
n = 2
x = Array.new(n)
dx = Array.new(n)
g = Array.new(4)
for i1 in 0 ... 4
g[i1] = Array.new(n)
end
time = 0.0
h = 0.01
x[0] = 0.0
x[1] = 0.0
# 計算と出力
for i1 in 0 ... 101
printf("time = %f, x = %f\n", time, x[0])
time = rkg(time, h, x, dx, g, n, &snx)
end
# -*- coding: UTF-8 -*-
import numpy as np
from math import *
############################################
# ルンゲ・クッタ法 dx/dt=f(t,x)
# time : 現在の時間
# h : 時間刻み幅
# x : 現在の状態
# dx : 微係数(f(t,x):subで計算する)
# g : 作業域(g[4][n])
# n : 微分方程式の次数
# sub : 微係数を計算する関数の名前
# return : time+h
# coded by Y.Suganuma
############################################
def rkg(time, h, x, dx, g, n, sub) :
h2 = 0.5 * h
sub(time, x, dx)
for i1 in range(0, n) :
g[0][i1] = h * dx[i1]
time += h2
for i1 in range(0, n) :
g[1][i1] = x[i1] + 0.5 * g[0][i1]
sub(time, g[1], dx)
for i1 in range(0, n) :
g[1][i1] = h * dx[i1]
for i1 in range(0, n) :
g[2][i1] = x[i1] + 0.5 * g[1][i1]
sub(time, g[2], dx)
for i1 in range(0, n) :
g[2][i1] = h * dx[i1]
time += h2
for i1 in range(0, n) :
g[3][i1] = x[i1] + g[2][i1]
sub(time, g[3], dx)
for i1 in range(0, n) :
g[3][i1] = h * dx[i1]
for i1 in range(0, n) :
x[i1] = x[i1] + (g[0][i1] + 2.0 * g[1][i1] + 2.0 * g[2][i1] + g[3][i1]) / 6.0
return time
############################################
# 微分方程式(ルンゲ・クッタ法)
# 例:d2x/dt+3dx/dt+2x=1
# coded by Y.Suganuma
############################################
# 微係数の計算 */
def snx(time, x, dx) :
dx[0] = x[1]
dx[1] = -2.0 * x[0] - 3.0 * x[1] + 1.0
# 初期設定
n = 2
x = np.array([0.0, 0.0], np.float)
dx = np.empty(n, np.float)
g = np.empty((4, n), np.float)
time = 0.0
h = 0.01
# 計算と出力
for i1 in range(0, 101) :
print("time = " + str(time) + ", x = " + str(x[0]))
time = rkg(time, h, x, dx, g, n, snx)
/**********************************/
/* 微分方程式(ルンゲ・クッタ法) */
/* 例:d2x/dt+3dx/dt+2x=1 */
/* coded by Y.Suganuma */
/**********************************/
using System;
class Program
{
static void Main()
{
Test1 ts = new Test1();
}
}
class Test1
{
public Test1()
{
/*
初期設定
*/
int n = 2;
double time = 0.0;
double h = 0.01;
double[] x = {0.0, 0.0};
double[] dx = new double [n];
double[][] g = new double [4][];
g[0] = new double[2];
g[1] = new double[2];
g[2] = new double[2];
g[3] = new double[2];
/*
計算と出力
*/
for (int i1 = 0; i1 < 101; i1++) {
Console.WriteLine("time = " + time + " x = " + x[0]);
time = rkg(time, h, x, dx, g, n, snx);
}
}
// 微係数の計算
int snx(double time, double[] x, double[] dx)
{
dx[0] = x[1];
dx[1] = -2.0 * x[0] - 3.0 * x[1] + 1.0;
return 0;
}
/********************************************/
/* ルンゲ・クッタ法 dx/dt=f(t,x) */
/* time : 現在の時間 */
/* h : 時間刻み幅 */
/* x : 現在の状態 */
/* dx : 微係数(f(t,x):snxで計算する) */
/* g : 作業域(g[4][n]) */
/* n : 微分方程式の次数 */
/* fn : 関数値を計算する関数 */
/* return : time+h */
/********************************************/
double rkg(double time, double h, double[] x, double[] dx, double[][] g,
int n, Func<double, double[], double[], int> fn)
{
double h2 = 0.5 * h;
fn(time, x, dx);
for (int i1 = 0; i1 < n; i1++)
g[0][i1] = h * dx[i1];
time += h2;
for (int i1 = 0; i1 < n; i1++)
g[1][i1] = x[i1] + 0.5 * g[0][i1];
fn(time, g[1], dx);
for (int i1 = 0; i1 < n; i1++)
g[1][i1] = h * dx[i1];
for (int i1 = 0; i1 < n; i1++)
g[2][i1] = x[i1] + 0.5 * g[1][i1];
fn(time, g[2], dx);
for (int i1 = 0; i1 < n; i1++)
g[2][i1] = h * dx[i1];
time += h2;
for (int i1 = 0; i1 < n; i1++)
g[3][i1] = x[i1] + g[2][i1];
fn(time, g[3], dx);
for (int i1 = 0; i1 < n; i1++)
g[3][i1] = h * dx[i1];
for (int i1 = 0; i1 < n; i1++)
x[i1] = x[i1] + (g[0][i1] + 2.0 * g[1][i1] + 2.0 * g[2][i1] + g[3][i1]) / 6.0;
return time;
}
}
''''''''''''''''''''''''''''''''''
' 微分方程式(ルンゲ・クッタ法) '
' 例:d2x/dt+3dx/dt+2x=1 '
' coded by Y.Suganuma '
''''''''''''''''''''''''''''''''''
Module Test
Sub Main()
'
' 初期設定
'
Dim n As Integer = 2
Dim time As Double = 0.0
Dim h As Double = 0.01
Dim x() As Double = {0.0, 0.0}
Dim dx(n) As Double
Dim g0(2) As Double
Dim g1(2) As Double
Dim g2(2) As Double
Dim g3(2) As Double
' 微係数の計算
Dim snx = Function(tm, v, dv)
dv(0) = v(1)
dv(1) = -2.0 * v(0) - 3.0 * v(1) + 1.0
Return 0
End Function
'
' 計算と出力
'
For i1 As Integer = 0 To 100
Console.WriteLine("time = " & time & " x = " & x(0))
time = rkg(time, h, x, dx, g0, g1, g2, g3, n, snx)
Next
End Sub
''''''''''''''''''''''''''''''''''''''''''''
' ルンゲ・クッタ法 dx/dt=f(t,x) '
' time : 現在の時間 '
' h : 時間刻み幅 '
' x : 現在の状態 '
' dx : 微係数(f(t,x):snxで計算する) '
' g0,g1,g2,g3 : 作業域(gi(n)) '
' n : 微分方程式の次数 '
' fn : 関数値を計算する関数 '
' return : time+h '
''''''''''''''''''''''''''''''''''''''''''''
Function rkg(time As Double, h As Double, x() As Double, dx() As Double,
g0() As Double, g1() As Double, g2() As Double, g3() As Double,
n As Integer, fn As Func(Of Double, Double(), Double(), Integer))
Dim h2 As Double = 0.5 * h
fn(time, x, dx)
For i1 As Integer = 0 To n-1
g0(i1) = h * dx(i1)
Next
time += h2
For i1 As Integer = 0 To n-1
g1(i1) = x(i1) + 0.5 * g0(i1)
Next
fn(time, g1, dx)
For i1 As Integer = 0 To n-1
g1(i1) = h * dx(i1)
Next
For i1 As Integer = 0 To n-1
g2(i1) = x(i1) + 0.5 * g1(i1)
Next
fn(time, g2, dx)
For i1 As Integer = 0 To n-1
g2(i1) = h * dx(i1)
Next
time += h2
For i1 As Integer = 0 To n-1
g3(i1) = x(i1) + g2(i1)
Next
fn(time, g3, dx)
For i1 As Integer = 0 To n-1
g3(i1) = h * dx(i1)
Next
For i1 As Integer = 0 To n-1
x(i1) = x(i1) + (g0(i1) + 2.0 * g1(i1) + 2.0 * g2(i1) + g3(i1)) / 6.0
Next
Return time
End Function
End Module
| 情報学部 | 菅沼ホーム | 目次 | 索引 |