티스토리 뷰

pointer, array, struct, enum, enum class...

이 정도만 하면 얼추 C++에서 객체 지향 프로그래밍을 하기 위한 준비는 끝마쳤다고 볼 수 있겠다. class에 관한 syntax는 OOP와 함께 다뤄볼 예정이다.

 

함수와 구조체를 사용하는 이유는 복잡한 반복되는 과정을 효율적으로 처리하기 위함이다. 이번 시간에는 주어진 입력이 정수, 실수, 허수인지를 알아서 분기하여 사칙연산을 수행할 수 있게 하는 계산기를 만들 예정이다. 더하기와 빼기는 비교적 쉬우므로, 곱하기와 나누기 정도만 구현해 보도록 하자.

 

1. 수를 담는 구조체 (타입은 enum으로 분기, union으로 한 수에는 하나의 타입 매칭)

2. 수를 로그에 출력하는 함수

3. 수의 실수 부분(real_component)과 허수 부분(complex_component)을 반환하는 함수

4. 복소수의 크기(magnitude)를 반환하는 함수

3. 두 수의 곱(multiply), 나눗셈(divide) 결과를 반환하는 함수

 

struct

struct number {
	enum number_type { integer, real, complex_num } number_type;
    union {
    	long integer_value,
        double real_value,
        struct {
        	double r, i;
        } complex_value;
    };
};

number의 구조는 해당 수를 분기해 주기 위한 열거형과 수의 유형에 따른 값을 하나만 가질 수 있게 하는 union으로 이루어져 있다.

 

수를 로그에 출력하는 함수

static void print(number const* n) {
	switch (n->number_type) {
	case number::number_type::integer:		cout << n->integer_value; break;
	case number::number_type::real:			cout << n->real_value; break;
	case number::number_type::complex_num:	cout << n->complex_value.r << " + " << n->complex_value.i << "i"; break;
	}
}

수의 타입으로 분기하여 로그에 찍어준다. 복소수는 실수부와 정수부를 나누어 a + bi 꼴로 출력한다.

 

실수부, 허수부 반환 함수

// 실수 부분 반환
static double real_component(number const* n) {
	switch (n->number_type) {
	default:
	case number::number_type::integer:	return n->integer_value;
	case number::number_type::real:		return n->real_value;
	case number::number_type::complex_num:	return n->complex_value.r;
	}
}

// 허수 부분 반환
static double imaginary_component(number const* n) {
	switch (n->number_type) {
	case number::number_type::complex_num:	return n->complex_value.i;
	default:								return 0;
	}
}

우리는 어느 타입의 숫자가 들어와도 계산할 수 있는 코드를 짜야하기 때문에, 허수부가 존재하지 않는 타입의 허수부는 0으로 처리한다.

 

복소수의 크기를 반환하는 함수

static double magnitude(double r, double i) {
	return sqrt(r*r + i*i);
}

복소수의 크기는 복소수의 곱과 나눗셈에서 중요한 역할을 한다. 곱에서는 크기 * 크기가 결과의 크기가 되고, 나눗셈에서는 크기 / 크기가 결과의 크기가 된다.

 

두 수의 곱, 나누셈을 반환하는 함수

static number multiply(number const* a, number const* b) {
	if (a->number_type == number::number_type::complex_num ||
	b->number_type == number::number_type::complex_num) {
		double r1 = real_component(a), i1 = imaginary_component(a),
		r2 = real_component(b), i2 = imaginary_component(b);
		double mag_r = magnitude(r1, i1) * magnitude(r2, i2);
		double a_r = atan2(i1, r1) + atan2(i2, r2);
		number n = {
			.number_type = number::number_type::complex_num,
			.complex_value = { mag_r * cos(a_r), mag_r * sin(a_r) }
		};
		return n;
	} else {
		number n = {
			.number_type = number::number_type::real,
			.real_value = real_component(a) * real_component(b)
		};

		return n;
	}
}

static number divide(number const* dividend, number const* divisor) {
	if (dividend->number_type == number::number_type::complex_num
	|| divisor->number_type == number::number_type::complex_num) {
		double r1 = real_component(dividend), i1 = imaginary_component(dividend),
			r2 = real_component(divisor), i2 = imaginary_component(divisor);
		double a_r = atan2(i1, r1) - atan2(i2, r2);
		double mag_r = magnitude(r1, i1) / magnitude(r2, i2);
		number n = { .number_type = number::number_type::complex_num,
			.complex_value = { mag_r * cos(a_r), mag_r * sin(a_r) } };
		return n;
	} else {
		number n = { .number_type = number::number_type::real,
			.real_value = real_component(dividend) / real_component(divisor) };
		return n;
	}
}

복소평면의 r, i 축을 통해 탄젠트 값을 알 수 있어 arctan로 각도를 구하고, 다시 cos와 sin을 이용해 계산한 값을 복소수로 반환해 준다.

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
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
글 보관함