どのようにしてプログラムを書いたのか。

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
carnage0216
記事: 20
登録日時: 6年前

どのようにしてプログラムを書いたのか。

#1

投稿記事 by carnage0216 » 5年前

プログラムの質問というより、なぜプログラムのように書けたのか詳しく知りたいと思い質問させて頂きました。
連立方程式を解く方法はわかったのですが、

なぜこのようにプログラムが書けたのか理由が知りたく実際のプログラムに値を入れて計算したのですがどうもうまくいきません。

例えば、k=0の時、i=0となります。d = a[k] / a[k][k]よりjは1となり、 a[j] -= a[k][j] * dは a[j] -= a[0][1] * 1より、 a[j]は a[0][1]となるため-2と、、、何を行なっているのか悩んでしまい全く理解ができません。

以下は全体の計算部分です。

どうか実際のプログラムに値をに代入して、変数の値が導かれるまでの過程を教えて頂けないでしょうか?

どうかよろしくお願いします。



コード:

// 前進消去

 for (k = 0; k < N -1; k++) {

 for (i = k + 1; i < N; i++) {

 d = a[i][k] / a[k][k];

 for (j = k + 1; j <= N; j++)

 a[i][j] -= a[k][j] * d;

 }

 }


全体のプログラムはこちらになります。

コード:

/*********************************************
 * 連立方程式の解法 ( ガウスの消去法 )
 *********************************************/
#include <iostream>  // for cout
#include <stdio.h>   // for printf()

// 元の数定義
#define N 4  // 3

using namespace std;

/*
 * 計算クラス
 */
class Calc
{
    double a[N][N + 1];

    // 各種変数
    double d;     // ダミー
    int i, j, k;  // LOOP インデックス

    public:
        // 連立方程式を解く(ガウスの消去法)
        void calcGaussElimination();
};

/*
 * 連立方程式を解く(ガウスの消去法)
 */
void Calc::calcGaussElimination()
{
    // 係数
    static double a[N][N + 1] = {
        //{ 2.0, -3.0,  1.0,  5.0},
        //{ 1.0,  1.0, -1.0,  2.0},
        //{ 3.0,  5.0, -7.0,  0.0}
        { 1.0, -2.0,  3.0, -4.0,  5.0},
        {-2.0,  5.0,  8.0, -3.0,  9.0},
        { 5.0,  4.0,  7.0,  1.0, -1.0},
        { 9.0,  7.0,  3.0,  5.0,  4.0}
    };

    // 元の連立方程式をコンソール出力
    for (i = 0; i < N; i++) {
        for (j = 0; j < N; j++)
            printf("%+fx%d ", a[i][j], j + 1);
        printf("= %+f\n", a[i][N]);
    }

    // 前進消去
    for (k = 0; k < N -1; k++) {
        for (i = k + 1; i < N; i++) {
            d = a[i][k] / a[k][k];
            for (j = k + 1; j <= N; j++)
                a[i][j] -= a[k][j] * d;
        }
    }

    // 後退代入
    for (i = N - 1; i >= 0; i--) {
        d = a[i][N];
        for (j = i + 1; j < N; j++)
            d -= a[i][j] * a[j][N];
        a[i][N] = d / a[i][i];
    }

    // 結果出力
    for (k = 0; k < N; k++)
        printf("x%d = %f\n", k + 1, a[k][N]);
}

/*
 * メイン処理
 */
int main()
{
    try
    {
        // 計算クラスインスタンス化
        Calc objCalc;

        // 連立方程式を解く(ガウスの消去法)
        objCalc.calcGaussElimination();
    }
    catch (...) {
        cout << "例外発生!" << endl;
        return -1;
    }

    // 正常終了
    return 0;
}

かずま

Re: どのようにしてプログラムを書いたのか。

#2

投稿記事 by かずま » 5年前

carnage0216 さんが書きました:
5年前
例えば、k=0の時、i=0となります。d = a[k] / a[k][k]よりjは1となり、 a[j] -= a[k][j] * dは a[j] -= a[0][1] * 1より、 a[j]は a[0][1]となるため-2と、、、何を行なっているのか悩んでしまい全く理解ができません。

コード:

[i] と書くと、イタリック体タグと解釈されて、
[i] は表示されず、以後、半角文字がすべて斜体になります。
[i] を表示したければ、御覧のように codeタグを使うなどの工夫が必要です。
コードをよく見てください。
k = 0 の時、i = 0 にはなりません。
i = k + 1 ですから、i = 1 となります。

コード:

d = a[i][k] / a[k][k] = a[1][0] / a[0][0] = -2
j = k + 1 = 1
a[i][j] -= a[k][j] * d より
  a[1][1] = 1
  a[1][2] = 14
  a[1][3] = -11
プログラムの理解のために、j = k + 1 を j = k にすると
  a[1][0] = 0
になることがわかります。
次のプログラムで確かめてください。

コード:

/*********************************************
 * 連立方程式の解法 ( ガウスの消去法 )
 *********************************************/
#include <iostream>  // for cout
#include <cstdio>    // for printf()

const int N = 4;       // 元の数定義

using namespace std;

class Calc {                      // 計算クラス
public:
    void calcGaussElimination();  // 連立方程式を解く(ガウスの消去法)
};

void print(int k, double d, double a[N][N+1])  // ★ デバッグプリント
{
	printf("--- k = %d, d = %g ---\n", k, d);
    for (int i = 0; i < N; i++) {         // 元の連立方程式をコンソール出力
        for (int j = 0; j < N; j++)
            printf("%+8g ", a[i][j]);
        printf("= %+8g\n", a[i][N]);
    }
}

void Calc::calcGaussElimination() // 連立方程式を解く(ガウスの消去法)
{
    static double a[N][N + 1] = { // 係数
        { 1.0, -2.0,  3.0, -4.0,  5.0},
        {-2.0,  5.0,  8.0, -3.0,  9.0},
        { 5.0,  4.0,  7.0,  1.0, -1.0},
        { 9.0,  7.0,  3.0,  5.0,  4.0}
    };

    for (int i = 0; i < N; i++) {         // 元の連立方程式をコンソール出力
        for (int j = 0; j < N; j++)
            printf("%+f x%d ", a[i][j], j + 1);
        printf("= %+f\n", a[i][N]);
    }
	cout << "[ 前進消去 ]\n";
    for (int k = 0; k < N -1; k++) {           // 前進消去
        for (int i = k + 1; i < N; i++) {
            double d = a[i][k] / a[k][k];
            for (int j = k; j <= N; j++)  // ★ k + 1 --> k
                a[i][j] -= a[k][j] * d;
			print(k, d, a);  // ★ 
        }
    }
    for (int i = N - 1; i >= 0; i--) {         // 後退代入
        double d = a[i][N];
        for (int j = i + 1; j < N; j++)
            d -= a[i][j] * a[j][N];
        a[i][N] = d / a[i][i];
    }
    for (int k = 0; k < N; k++)                // 結果出力
        printf("x%d = %f\n", k + 1, a[k][N]);
}

int main()   // メイン処理
{
    try {
        Calc objCalc;    // 計算クラスインスタンス化
        objCalc.calcGaussElimination();      // 連立方程式を解く
    }
    catch (...) {
        cout << "例外発生!" << endl;
        return -1;
    }
    return 0;  // 正常終了
}
実行結果

コード:

+1.000000 x1 -2.000000 x2 +3.000000 x3 -4.000000 x4 = +5.000000
-2.000000 x1 +5.000000 x2 +8.000000 x3 -3.000000 x4 = +9.000000
+5.000000 x1 +4.000000 x2 +7.000000 x3 +1.000000 x4 = -1.000000
+9.000000 x1 +7.000000 x2 +3.000000 x3 +5.000000 x4 = +4.000000
[ 前進消去 ]
--- k = 0, d = -2 ---
      +1       -2       +3       -4 =       +5
      +0       +1      +14      -11 =      +19
      +5       +4       +7       +1 =       -1
      +9       +7       +3       +5 =       +4
--- k = 0, d = 5 ---
      +1       -2       +3       -4 =       +5
      +0       +1      +14      -11 =      +19
      +0      +14       -8      +21 =      -26
      +9       +7       +3       +5 =       +4
--- k = 0, d = 9 ---
      +1       -2       +3       -4 =       +5
      +0       +1      +14      -11 =      +19
      +0      +14       -8      +21 =      -26
      +0      +25      -24      +41 =      -41
--- k = 1, d = 14 ---
      +1       -2       +3       -4 =       +5
      +0       +1      +14      -11 =      +19
      +0       +0     -204     +175 =     -292
      +0      +25      -24      +41 =      -41
--- k = 1, d = 25 ---
      +1       -2       +3       -4 =       +5
      +0       +1      +14      -11 =      +19
      +0       +0     -204     +175 =     -292
      +0       +0     -374     +316 =     -516
--- k = 2, d = 1.83333 ---
      +1       -2       +3       -4 =       +5
      +0       +1      +14      -11 =      +19
      +0       +0     -204     +175 =     -292
      +0       +0       +0 -4.83333 = +19.3333
x1 = 1.000000
x2 = 3.000000
x3 = -2.000000
x4 = -4.000000

かずま

Re: どのようにしてプログラムを書いたのか。

#3

投稿記事 by かずま » 5年前

コード:

   1 x1 -2 x2 +3 x3 -4 x4 = 5    --(1)
  -2 x1 +5 x2 +8 x3 -3 x4 = 9    --(2)
   5 x1 +4 x2 +7 x3 +1 x4 = -1   --(3)
   9 x1 +7 x2 +3 x3 +5 x4 = 4    --(4)
前進消去

コード:

(1) を使って、(2)(3)(4) の x1 の係数を 0 にする。
 (2) - (1) * (-2 / 1)  --> (2)
--- k = 0, d = -2 ---
      +1       -2       +3       -4 =       +5
      +0       +1      +14      -11 =      +19
      +5       +4       +7       +1 =       -1
      +9       +7       +3       +5 =       +4
 (3) - (1) * (5 / 1)   --> (3)
--- k = 0, d = 5 ---
      +1       -2       +3       -4 =       +5
      +0       +1      +14      -11 =      +19
      +0      +14       -8      +21 =      -26
      +9       +7       +3       +5 =       +4
 (4) - (1) * (9 / 1)   --> (4)
--- k = 0, d = 9 ---
      +1       -2       +3       -4 =       +5
      +0       +1      +14      -11 =      +19
      +0      +14       -8      +21 =      -26
      +0      +25      -24      +41 =      -41

コード:

新しい (2) を使って、(3)(4) の x2 の係数を 0 にする。
 (3) - (2) * (14 / 1)   --> (3)
--- k = 1, d = 14 ---
      +1       -2       +3       -4 =       +5
      +0       +1      +14      -11 =      +19
      +0       +0     -204     +175 =     -292
      +0      +25      -24      +41 =      -41
 (4) - (2) * (25 / 1)   --> (4)
--- k = 1, d = 25 ---
      +1       -2       +3       -4 =       +5
      +0       +1      +14      -11 =      +19
      +0       +0     -204     +175 =     -292
      +0       +0     -374     +316 =     -516

コード:

新しい (3) を使って、(4) の x3 の係数を 0 にする。
 (4) - (3) * (-374 / -204)   --> (4)
--- k = 2, d = 1.83333 ---
      +1       -2       +3       -4 =       +5   --(1)
      +0       +1      +14      -11 =      +19   --(2)
      +0       +0     -204     +175 =     -292   --(3)
      +0       +0       +0 -4.83333 = +19.3333   --(4)
後退代入

コード:

(4) から x4 = 19.3333 / -4.83333 = -4
(3) に x4 を代入して、x3 = (-292 - x4 * 175) / -204 = -2
(2) に x3 と x4 を代入して、x2 = (19 - x3*14 - x4*-11) / 1 = 3
(1) に x2, x3, x4 を代入して、x1 = (5 - x2*-2 - x3*3 - x4*-4) / 1 = -4

よもやま
記事: 68
登録日時: 8年前
連絡を取る:

Re: どのようにしてプログラムを書いたのか。

#4

投稿記事 by よもやま » 5年前

carnage0216 さんが書きました:
5年前
プログラムの質問というより、なぜプログラムのように書けたのか詳しく知りたいと思い質問させて頂きました。
連立方程式を解く方法はわかったのですが、

なぜこのようにプログラムが書けたのか理由が知りたく実際のプログラムに値を入れて計算したのですがどうもうまくいきません。

関連する元記事情報ぐらい書いておきましょう。
連立方程式の計算の演算回路での過程について。
今回も前回こちらに投稿された記事は放置ですか??
元々投稿してあったサイトの記事にはベストアンサーがついてましたけど。
連立方程式をつくプログラムの解読

carnage0216
記事: 20
登録日時: 6年前

Re: どのようにしてプログラムを書いたのか。

#5

投稿記事 by carnage0216 » 5年前

どうもありがとうございます。大変勉強になります。

返信

“C言語何でも質問掲示板” へ戻る