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을 이용해 계산한 값을 복소수로 반환해 준다.
'Computer Science and Engineering > OOP (Object Oriented Programming)' 카테고리의 다른 글
[OOP, C++] Class 기초 - 선언, 초기화, 사용 (0) | 2023.05.22 |
---|---|
[Syntax, C++] Reference(&) - 참조란? (0) | 2023.05.22 |
[Syntax, C++] struct를 활용하여 다각형의 둘레의 길이 구하기 (0) | 2023.04.27 |
[Syntax, C++] struct, enum class를 활용하여 날짜(D - day) 계산하기 (0) | 2023.04.27 |
[Syntax, C++] Array에서의 Pointer (0) | 2023.03.21 |