Gauss Jordan Elimination 구현 (C++)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <iostream>
#define sz 5
void printAugMtrx(double augMtrx[sz][sz+1], int size);
void divAugMtrx(double augMtrxRow[sz + 1], int sizedouble op);
void minAugMtrx(double toRow[sz + 1], double opRow[sz + 1], int sizedouble op);
void rowCG(double augMtrx[sz][sz + 1], int sizeint r1, int r2);
void pivot(double augMtrx[5][6], int size);
int main() {
    double mtrx[sz][sz+1= {
1.07.03.02.01.049.0 },
2.01.02.07.02.038.0 },
3.02.09.04.05.050.0 },
7.01.0,7.01.04.044.0 },
9.08.0,7.06.05.0102.0 },
    };
    printAugMtrx(mtrx, sz);
    pivot(mtrx, sz);
}
void printAugMtrx(double augMtrx[sz][sz+1], int size) {
    std::cout << "행렬 출력\n";
    for (int i = 0; i < size; i++) {
        for (int j = 0; j < size+1; j++) {
            printf(" %4.3f ", augMtrx[i][j]);
        }
        std::cout << "\n";
    }
}
void divAugMtrx(double augMtrxRow[sz + 1], int sizedouble op) {
    for (int i = 0; i < sz + 1; i++) {
        augMtrxRow[i] /= op;
    }
}
void minAugMtrx(double augMtrxRow[sz + 1], double opRow[sz + 1], int sizedouble op) {
    for (int i = 0; i < sz + 1; i++) {
        augMtrxRow[i] -= opRow[i]*op;
    }
}
void pivot(double augMtrx[sz][sz+1], int size) {
    //계수가 가장 큰 행을 구하기
    for (int i = 0; i < sz; i++) { //각 열에 대해 피봇팅
        double mx = augMtrx[i][i];
        int mid = i;
        for (int j = i+1; j < sz; j++) {
            if (augMtrx[j][i] > mx) {
                mx = augMtrx[j][i];
                mid = j;
            }
        }
        rowCG(augMtrx, sz, i, mid);
        std::cout << i+1<<"번째 pivot 수행.. \n";
        for (int j = i; j < sz; j++) {
            divAugMtrx(augMtrx[j], sz + 1, mx);
        }
        for (int j = i + 1; j < sz; j++) {
            minAugMtrx(augMtrx[j], augMtrx[i], sz, augMtrx[j][i]);
        }
        printAugMtrx(augMtrx, sz);
    }
    std::cout << "상삼각행렬이 완성되었습니다. 후진대입법을 적용해 해를 구합니다.\n";
    for (int j = sz - 1; j >= 0; j--) {
        for (int k = 0; k < j; k++) {
            minAugMtrx(augMtrx[k], augMtrx[j], sz, augMtrx[k][j]);
        }
    }
    printAugMtrx(augMtrx, sz);
    std::cout << "따라서 해당 연립방정식의 해는 ...\n";
    for (int i = 0; i < sz; i++) {
        std::cout << "x"<<i+1<<" = "<<augMtrx[i][sz] <<"\n";
    }
}
void rowCG(double augMtrx[sz][sz + 1], int sizeint r1, int r2) {
    double tmp;
    for (int i = 0; i < sz + 1; i++) {
        tmp = augMtrx[r1][i];
        augMtrx[r1][i] = augMtrx[r2][i];
        augMtrx[r2][i] = tmp;
    }
}
cs

실행 결과

x1 = 3, x2 = 5, x3 = 1, x4 = 3, x5 = 2로 연립 방정식의 해를 구할 수 있었습니다.

후기
스크립트형 언어인 파이썬이나 매트랩을 사용했다면 훨씬 더 구현이 쉬웠을 것 같습니다. 행렬 계산과 관련된 부분이라 그러한 점이 더욱 체감되었습니다. 부동소수점 오차에 대해 개선해야 할 것 같습니다.