학교수업, CS/수치해석

연립방정식(가우스 조단의 피보팅, 가우스 자이달 방법)

빨대도둑 2022. 11. 30. 12:45

가우스 조단의 피보팅

연립 방정식에서는 각 방정식들 간의 덧셈이나 뺄셈을 통하여 서로 동치인 방정식들을 만들 수 있다. 즉 어떤 방정식에 일정한 수를 곱하여 다른 방정식과 더하거나 빼는 과정을 거쳐서 만들어진 새로운 방정식도 이전의 방정식과 같은 해를 가진다.

<수식>

#include <stdio.h>

void main() {
	int i, j, k, num_eq, num_var;
	double coeff[20][20], known[20];

	printf("Enter the Number of Eqations.: ");
	scanf_s("%d", &num_eq);
	printf("Enter the Number of Variables.: ");
	scanf_s("%d", &num_var);

	for (i = 0; i < num_eq; i++) {
		printf("****************************\n");
		printf("Enter the Coefficients of eq.%d\n", i + 1);
		for (j = 0; j < num_var; j++) {
			printf("Coefficient of variable %d.", j + 1);
			scanf_s("%lf", &coeff[i][j]);
		}
		printf("Enter the known Value of eq. %d :", i + 1);
		scanf_s("%lf", &known[i]);
	}
	printf("*****************************");

	printf("\n\n Entered Equartions :\n");

	for (i = 0; i < num_eq; i++) {
		for (j = 0; j < num_var; j++) {
			printf("%10.3lf*X%d", coeff[i][j], j + 1);
			if (j != num_var - 1)printf("+");
			else printf("=");
		}
		printf("%10.3lf\n", known[i]);
	}

	void gauss_jordan_pivoting(coeff, known, num_eq, num_var);

	printf("\n\n*****************************\n");
	printf("Results:\n");
	for (i = 0; i < num_eq; i++) {
		for (j = 0; j < num_var; j++)
			printf("%10.3lf*X%d", coeff[i][j], j + 1);
		printf("%10.3lf\n", known[i]);
	}
}

void gauss_jordan_pivoting(coeff, known, num_eq, num_var)

double coeff[20][20], known[20];
int num_eq, num_var;
{
	int pivot_eq, eq2, var, max_index;
	double max_value, ftemp;

	for (pivot_eq = 0; pivot_eq < num_eq; pivot_eq++) {

		max_index = 0;
		max_value = coeff[pivot_eq][0];
		for (var = 0; var < num_var; var++)

			if (coeff[pivot_eq][var] * coeff[pivot_eq][var] > max_value * max_value) {
				max_index = var;
				max_value = coeff[pivot_eq][var];
			}

		for (var = 0; var < num_var; var++)
			coeff[pivot_eq][var] /= max_value;
		known[pivot_eq] /= max_value;

		for (eq2 = 0; eq2 < num_eq; eq2++) {
			ftemp = coeff[eq2][max_index];
			if (eq2 != pivot_eq) {
				for (var = 0; var < num_var; var++)

					coeff[eq2][var] -= ftemp * coeff[pivot_eq][var];
				known[eq2] -= ftemp * known[pivot_eq];
			}
		}

	}
}

 


가우스 자이달의 방법

일종의 반복 계산법이다. 반복 계산법은 해를 계산 초기에 임의로 가정하고, 이때 가정한 시험적인 해를 반복 계산 알고리즘을 통해 단계적으로 개선해 나감으로써 주어진 연립 방정식의 근사해를 구하는 방식이다.

가우스 조단의 방식 등의 직접 해법들은 방정식의 갯수가 15~20개 정도의 비교적 작은 연립 일차 방적식에 응용도리 때 상당히 정확한 해를 가져다줄 수 있는 방식이다. 하지만 이 방법은 미지수의 개수가 많은 큰 연립 방정식의 경우 산술 연산의 수가 많아 계산 시간이 많이 걸리고 또한 개개연산에서 발생하는 오차가 누적되어 부정확한 해를 얻을 수 도 있다

반복 계산법은 큰 연립 방정식의 해를 구하기 위한 한 방법으로서 이 방법은 이론적으로는 산술 연산의 수가 무한대지만 실제상으로는 직접 해법에 요구되는 것보다 훨씬 적은 수의 산술 연산으로 주어진 연립방정식의 해를 얻을 수 있기 때문에 계산 시간을 절약할 수 있다는 이점이 있다. 또한 반복 계산법은 문제에 따라서 직접 해법에 비해 계산에 요구되는 기억 용량이 줄어든다. 

  1. 각 미지수들에게 초기 값들을 할당한다. 초기값드링 방정식의 해에 가까우면 가까울수록 빨리 만족할 만한 해를 구할 수 있다
  2. 첫번째 방정식에서 계수의 크기가 가장 큰 미지수를 골라 그에 대해서 방정식을 푼다. 선택된 미지수를 제외한 미지수들에 초기값을 대입해서 그 미지수의 값을 구한다
  3. 두 번째 방정식에서 계산된 미지수를 제외한 나머지 미지수들 중에서 계수가 가장 큰 것을 골라 그에 대해서 방정식을 푼다. 이때 바로 앞의 계산 결과도 함께 대입한다
  4. 세 번째 방정식에서 계산된 것들을 제외한 나머지 미지수 중에서 계수가 가장 큰 것을 골라 그에 대해서 방정식을 푼다. 이제까지 나온 결과도 이용한다
  5. 다시 처음의 방정식으로 돌아가서 지금까지의 결과를 이용해서 다시 처음의 변수에 대해서 풀어 나간다
  6. 이러한 방식으로 원하는 정확도를 얻을 때 까지 계산을 반복해 나간다

<수식>

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

void gauss_seidal_method(coeff, known, num_eq, num_var, variable, error_bound)

float coeff[20][20], known[20], variable[20];
float error_bound;
int num_eq, num_var;

{
    int var, eq, max_index[20], calculated_flag[20];
    float sum, max_value[20], pre_value, difference;

    for (var = 0; var < num_var; var++)
        calculated_flag[var] = 0;

    for (eq = 0; eq < num_eq; eq++) {
        for (var = 0; var < num_var; var++)
            if (calculated_flag[var] == 0) {
                max_index[eq] = var;
                max_value[eq] = coeff[eq][var];
                break;
            }
        for (var = max_index[eq] + 1; var < num_var; var++)

            if ((coeff[eq][var] * coeff[eq][var] > max_value[eq] * max_value[eq]) && 
            (calculated_flag[var] == 0)) {
                max_index[eq] = var;
                max_value[eq] = coeff[eq][var];
            }
        calculated_flag[max_index[eq]] = 1;
    }
    do {
        difference = 0.0;

        for (eq = 0; eq < num_eq; eq++) {
            sum = 0;
            for (var = 0; var < num_var; var++)
                sum += coeff[eq][var] * variable[var];

            pre_value = variable[max_index[eq]];
            variable[max_index[eq]] = (known[eq] - sum + coeff[eq][max_index[eq]] * 
            variable[max_index[eq]]) / coeff[eq][max_index[eq]];

            difference += fabs(pre_value - variable[max_index[eq]]);
        }
        difference /= num_var;
    } while (difference > error_bound);
    printf("\ncalculation reached threshold \n");

}

void main() {
    int i, j, num_eq, num_var;
    float coeff[20][20], known[20], var[20] ;
    float error_bound ;

    printf("Enter the Number of Equtions. :");
    scanf_s("%d", &num_eq);
    printf("Enter the Number of Variables. :");
    scanf_s("%d", &num_var);

    for (i = 0; i < num_eq; i++) {
        printf("******************************\n");
        printf("Enter the Coefficients of eq. %d.\n", i + 1);
        for (j = 0; j < num_var; j++) {
            printf("Coefficients of variable. %d. : ", j + 1);
            scanf_s("%f", &coeff[i][j]);
        }
        printf("Enter the Know value of eq. %d. : ", i + 1);
        scanf_s("%f", &known[i]);
    }

    printf("******************************\n");
    printf("Enter the initial value of variables .\n");
    for (i = 0; i < num_var; i++) {
        printf("initial value of variable. %d. : ", i + 1);
        scanf_s("%f", &var[i]);
    }

    printf("Enter the bound of error : ");
    scanf_s("%f", &error_bound);

    printf("******************************\n");
    printf("\n\n Entered Equations :\n");
    for (i = 0; i < num_eq; i++) {
        for (j = 0; j < num_var; j++) {
            printf("%10.3f * X%d", coeff[i][j], j + 1);
            if (j != num_var - 1) printf("+");
            else printf("=");
        }
        printf("%10.3f\n", known[i]);
    }
    printf("******************************\n");
    printf("Entered initial values :\n");
    for (i = 0; i < num_var; i++)
        printf("X%d = %.3f\n", i + 1, var[i]);
    printf("Entered error bound: %.3f\n", error_bound);

    gauss_seidal_method(coeff, known, num_eq, num_var, var, error_bound);

    printf("******************************\n");
    printf("Results: \n");
    for (i = 0; i < num_var; i++)
        printf("variable %d is %10.3f\n", i + 1, var[i]);
}