Lab 6-3: Enhanced Complex Number Calculator (20%)

  • 輸入:
    1. double 格式輸入複數的實數及虛數部分,以空格分開,一行輸入一個複數
    2. char 格式輸入複數的運算子,包含 +-*/,一行輸入一個運算子
    3. 複數與運算子以交錯的方式輸入,一行輸入一個複數接著一個運算子,倒數一行為複數
    4. 在任一行輸入 Ctrl+D 結束程式
    • Windows 請輸入 Ctrl+Z (會在螢幕上顯示 ^Z) 再輸入 Enter (Format 中的 ) 結束程式
    1. 程式輸入以行為單位,每行輸入為任何有效的 string 格式
  • 輸出:
    1. 顯示運算複數的結果
    2. 複數的格式為 (-)<real result> (+|-) (<imag result>i)
    3. 若輸入運算子、需顯示之前運算的結果,如 Example 的範例
    4. 若使用者輸入的複數或運算子不正確,則顯示錯誤訊息 Error: Invalid input 並結束程式
  • 檔名:lab6-3_<學號>.cpp (e.g. lab6-3_106062802.cpp)

注意事項:

  • 程式不會輸出任何使用者提示,只會輸出程式結果或錯誤訊息
  • 程式僅需處裡輸入錯誤的例外狀況,如輸入的複數或運算子不正確,其餘錯誤不須處裡
  • 請基於 pseudo code 提供的 mainComplex_Calc::set_input 進行修改來處理輸入與輸出
  • 程式需要於 10 秒內完成,所有的測資皆會保證於 10 秒內完成

Format

<real 1> <imag 1>⏎
<result 1>
<op 1>⏎
<result 1>
<real 2> <imag 2>⏎
<result 2>
<op 2>⏎
<result 2>
...
<real n-1> <imag n-1>⏎
<result n-1>
<op n-1>⏎
<result n-1>
<real n> <imag n>⏎
<result n>
^Z⏎

Example

Normal

$ ./a.out
1.0 0.0⏎
1
^Z⏎
$ ./a.out
0.0 1.0⏎
0 + 1i⏎
^Z⏎
$ ./a.out
1.0 0.0⏎
1
+⏎
1
^Z⏎
$ ./a.out
^Z⏎
$ ./a.out
1.0 0.0⏎
1
+⏎
1
2.0 1.1⏎
3 + 1.1i
-⏎
3 + 1.1i
-3.0 -2.2⏎
6 + 3.3i
*⏎
6 + 3.3i
4.3 2.1⏎
18.87 + 26.79i
/⏎
18.87 + 26.79i
-1.2 -3.4⏎
-8.74846 + 2.46231i
^Z⏎
$ ./a.out
1.0 0.0⏎
1
+⏎
1
2.0 1.1⏎
3 + 1.1i
-⏎
3 + 1.1i
-3.0 -2.2⏎
6 + 3.3i
*⏎
6 + 3.3i
4.3 2.1⏎
18.87 + 26.79i
/⏎
18.87 + 26.79i
-1.2 3.4⏎
5.26477 - 7.40815i
^Z⏎
$

Exception Handling

$ ./a.out
+⏎
Error: Invalid input
$
$ ./a.out
1.0 0.0⏎
1
1.0 0.0⏎
Error: Invalid input
$
$ ./a.out
1.0 0.0⏎
1
+⏎
1
+⏎
Error: Invalid input
$
$ ./a.out
1.0 2.0 3.0⏎
Error: Invalid input
$
$ ./a.out
1.0 2.0⏎
1 + 2i
sdafsdagret⏎
Error: Invalid input
$
$ ./a.out
sdoifjwepoirjpwoie⏎
Error: Invalid input
$

Pseudo Code

#include <iostream>
#include <string>
#include <sstream>
#include <cmath>

using namespace std;

class Complex_Calc;

class Complex
{
private:
    // data members
    // save the real and imaginary parts of the complex number
    // with `double` precision
    double m_real;
    double m_imag;

public:
    // Constructor, initializes real and imaginary parts
    Complex(const double &arg_real = 0.0, const double &arg_imag = 0.0);
    // Copy constructor
    Complex(const Complex &arg_c);
    // assignment operator
    Complex &operator=(const Complex &arg_c);
    // add assignment operator
    Complex &operator+=(const Complex &arg_c);
    // subtract assignment operator
    Complex &operator-=(const Complex &arg_c);
    // multiply assignment operator
    Complex &operator*=(const Complex &arg_c);
    // divide assignment operator
    Complex &operator/=(const Complex &arg_c);
    // add function
    Complex operator+(const Complex &arg_c) const;
    // subtract function
    Complex operator-(const Complex &arg_c) const;
    // multiply function
    Complex operator*(const Complex &arg_c) const;
    // divide function
    Complex operator/(const Complex &arg_c) const;
    // cout `<<` operator for print complex number
    // note: be careful about the format of output
    friend ostream &operator<<(ostream &arg_os, const Complex &arg_c);
    // cin `>>` operator for input complex number
    // note: use `>>` to parse the string to double,
    // use `istream::fail()` to check the conversion is successful
    // and use `istream::eof()` to check the is parse to the end of line
    friend istream &operator>>(istream &arg_is, Complex &arg_c);

    friend class Complex_Calc;
};

// Complex calculator class declaration
class Complex_Calc
{
private:
    // define current value
    Complex m_curr_val;
    // define input value
    Complex m_input_val;
    // define operation
    // `+`, `-`, `*`, `/`, and `=`
    char m_op;
    // define input status, truns `op` for true and turns `value` for false
    bool m_op_input;
    // calculate result
    void _calc_result();
    // operation functions
    // set activation op to add
    void _add();
    // set activation op to subtract
    void _sub();
    // set activation op to multiply
    void _mul();
    // set activation op to divide
    void _div();
    // set activation op to assign
    void _assign();

public:
    // Constructor
    Complex_Calc();
    // Copy constructor
    Complex_Calc(const Complex_Calc &arg_int_calc);

    // Destructor
    ~Complex_Calc(){}; // no need to do anything

    // set input value or operation
    // as the same as the user input number or operation
    // into the calculator
    void set_input(const string &arg_input);

    // cout `<<` operator for print calculator status
    // note: be careful about the format of output
    friend ostream &operator<<(ostream &arg_os, const Complex_Calc &arg_comp_calc);
};

// error and exit
void error_and_exit()
{
    cerr << "Error: Invalid input" << endl;
    exit(1);
}

void Complex_Calc::set_input(const string &arg_input)
{
    // input is empty, read again
    if (arg_input.empty())
    {
        return;
    }
    // input is a operator in right turn

        // set the activated operation
        // as the same as the user press the op button

        // set to 'input a complex number' turn

    // input is a complex number in right turn
    // as the same as the user type a number
    // it performs as the same as the user pressed the '=' button
    // if the input is the first input
    // thus, we initialize the m_op to '='

    // else, input is invalid
    else
    {
        error_and_exit();
    }
}

// main function

int main()
{
    // create an instance of the class
    Complex_Calc calc;
    string input;
    while (getline(cin, input))
    {
        calc.set_input(input);
        cout << calc << endl;
    }
}

Reference Code:

林元鴻(110021120)

#include <iostream>
#include <string>
#include <sstream>
#include <cmath>

using namespace std;

class Complex_Calc;

class Complex
{
private:
    // data members
    // save the real and imaginary parts of the complex number
    // with `double` precision
    double m_real;
    double m_imag;

public:
    // Constructor, initializes real and imaginary parts
    Complex(const double &arg_real = 0.0, const double &arg_imag = 0.0)
    {
        m_real = arg_real;
        m_imag = arg_imag;
    }
    // Copy constructor
    Complex(const Complex &arg_c)
    {
        m_real = arg_c.m_real;
        m_imag = arg_c.m_imag;
    }
    // assignment operator
    Complex &operator=(const Complex &arg_c)
    {
        m_imag = arg_c.m_imag;
        m_real = arg_c.m_real;
        return *this;
    }
    // add assignment operator
    Complex &operator+=(const Complex &arg_c)
    {
        m_imag = m_imag + arg_c.m_imag;
        m_real = m_real + arg_c.m_real;
        return *this;
    }
    // subtract assignment operator
    Complex &operator-=(const Complex &arg_c)
    {
        m_imag = m_imag - arg_c.m_imag;
        m_real = m_real - arg_c.m_real;
        return *this;
    }
    // multiply assignment operator
    Complex &operator*=(const Complex &arg_c)
    {
        Complex p;
        p.m_real = (m_real * arg_c.m_real) - (m_imag * arg_c.m_imag);
        p.m_imag = (m_real * arg_c.m_imag) + (m_imag * arg_c.m_real);
        m_imag = p.m_imag;
        m_real = p.m_real;
        return *this;
    }
    // divide assignment operator
    Complex &operator/=(const Complex &arg_c)
    {
        Complex p;
        p.m_real = (arg_c.m_real * m_real + m_imag * arg_c.m_imag) 
            / (arg_c.m_real * arg_c.m_real + arg_c.m_imag * arg_c.m_imag);
        p.m_imag = (arg_c.m_real * m_imag - m_real * arg_c.m_imag) 
            / (arg_c.m_real * arg_c.m_real + arg_c.m_imag * arg_c.m_imag);
        m_imag = p.m_imag;
        m_real = p.m_real;
        return *this;
    }
    // add function
    Complex operator+(const Complex &arg_c) const
    {
        Complex p;
        p.m_imag = m_imag + arg_c.m_imag;
        p.m_real = m_real + arg_c.m_real;
        return p;
    }
    // subtract function
    Complex operator-(const Complex &arg_c) const
    {
        Complex p;
        p.m_imag = m_imag - arg_c.m_imag;
        p.m_real = m_real - arg_c.m_real;
        return p;
    }
    // multiply function
    Complex operator*(const Complex &arg_c) const
    {
        Complex p;
        p.m_real = (m_real * arg_c.m_real) - (m_imag * arg_c.m_imag);
        p.m_imag = (m_real * arg_c.m_imag) + (m_imag * arg_c.m_real);
        return p;
    }
    // divide function
    Complex operator/(const Complex &arg_c) const
    {
        Complex p;
        p.m_real = (arg_c.m_real * m_real + m_imag * arg_c.m_imag) 
            / (arg_c.m_real * arg_c.m_real + arg_c.m_imag * arg_c.m_imag);
        p.m_imag = (arg_c.m_real * m_imag - m_real * arg_c.m_imag) 
            / (arg_c.m_real * arg_c.m_real + arg_c.m_imag * arg_c.m_imag);
        return p;
    }

    friend ostream &operator<<(ostream &arg_os, const Complex &arg_c)
    {
        if (arg_c.m_imag == 0)
            arg_os << arg_c.m_real;
        else if (arg_c.m_imag > 0)
            arg_os << arg_c.m_real << " + " << arg_c.m_imag << 'i';
        else
            arg_os << arg_c.m_real << " - " << (-1) * (arg_c.m_imag) << 'i';
        return arg_os;
    }

    friend istream &operator>>(istream &arg_is, Complex &arg_c)
    {
        string str_x, str_y, temp;

        if (getline(arg_is, str_x, ' '))
        {
            if (getline(arg_is, str_y, '\n'))
            {
                arg_c.m_real = stod(str_x);
                arg_c.m_imag = stod(str_y);
            }
        }

        return arg_is;
    }
    friend class Complex_Calc;
};

// Complex calculator class declaration
class Complex_Calc
{
private:
    // define current value
    Complex m_curr_val;
    // define input value
    Complex m_input_val;
    // define operation
    // `+`, `-`, `*`, `/`, and `=`
    string m_op;
    // calculate result
    void _calc_result()
    {
        switch (m_op[0])
        {
        case '+':
            _add();
            break;
        case '-':
            _sub();
            break;
        case '*':
            _mul();
            break;
        case '/':
            _div();
            break;
        case '=':
            _assign();
            break;
        }
        return;
    }
    // operation functions
    // add the input value to the current value
    void _add()
    {
        m_curr_val += m_input_val;
        return;
    }
    // subtract the input value from the current value
    void _sub()
    {
        m_curr_val -= m_input_val;
        return;
    }
    // multiply the input value with the current value
    void _mul()
    {
        m_curr_val *= m_input_val;
        return;
    }
    // divide the current value by the input value
    void _div()
    {
        m_curr_val /= m_input_val;
        return;
    }
    // assign the input value to the current value
    void _assign()
    {
        m_curr_val = m_input_val;
        return;
    }

public:
    // Constructor
    Complex_Calc(const Complex &arg_curr_val = Complex(0, 0),
                 const Complex &arg_input_val = Complex(0, 0),
                 const string op = "=")
    {
        m_curr_val = arg_curr_val;
        m_input_val = arg_input_val;
        m_op = op;
    }
    //(const Complex &arg_curr_val = (0, 0),
    // const Complex &arg_input_val = (0,0),
    // const char op = '=')
    // Copy constructor
    Complex_Calc(const Complex_Calc &arg_int_calc)
    {
        m_curr_val = arg_int_calc.m_curr_val;
        m_input_val = arg_int_calc.m_input_val;
        m_op = arg_int_calc.m_op;
    }

    // Destructor
    ~Complex_Calc(){}; // no need to do anything

    // set input value or operation
    void set_input(const string &arg_input);

    // cout `<<` operator for print calculator status
    // note: be careful about the format of output
    friend ostream &operator<<(ostream &arg_os, const Complex_Calc &arg_comp_calc)
    {
        arg_os << arg_comp_calc.m_curr_val;
        return arg_os;
    }
};

// parse the test cases, do not modify belows
void error_and_exit()
{
    cout << "Error: Invalid input" << endl;
    exit(1);
}
void Complex_Calc::set_input(const string &arg_input)
{
    // input is empty, read again
    if (arg_input.empty())
    {
        error_and_exit();
        return;
    }
    // input is a operation
    else if (arg_input == "+" || arg_input == "-" 
        || arg_input == "*" || arg_input == "/" || arg_input == "=")
    {
        m_op = arg_input;
    }
    // input is a complex number
    // as the same as the user type a number
    // it performs as the same as the user pressed the '=' button
    // if the input is the first input
    // thus, we initialize the m_op to '='
    else
    {
        stringstream ss(arg_input);
        ss >> m_input_val;
        if (m_input_val.m_imag == 0 && m_input_val.m_real == 0 && m_op == "/")
        {
            error_and_exit();
        }
        _calc_result();
    }
}

// main function
bool test(string input, int n)
{
    if (n % 2 == 0)
    {
        int t = 0;
        for (int i = 0; i < input.size(); i++)
        {
            if (input[i] == ' ')
            {
                t++;
            }
        }
        if (t != 1)
        {
            return false;
        }

        double real, imag;
        stringstream ss(input);
        ss >> real;

        if (ss.fail()) // if fail return false
        {
            return false;
        }

        ss >> imag;
        if (ss.fail())
        {
            return false;
        }

        if (!ss.eof()) // if it is not the end of file return false
        {
            return false;
        }
    }
    else
    {
        if (input.size() != 1)
        {
            return false;
        }
        else if (input[0] != '+' && input[0] != '-' 
            && input[0] != '*' && input[0] != '/')
        {
            return false;
        }
    }
    return true;
}
int main()
{
    int n = 0;
    // create an instance of the class
    Complex_Calc calc;
    string input;
    while (getline(cin, input))
    {
        if (!(test(input, n)))
        {
            error_and_exit();
        }
        calc.set_input(input);
        cout << calc << endl;
        n++;
    }
}

陳誼倫(110021127)

#include <iostream>
#include <string>
#include <sstream>
#include <cmath>
#include <vector>

using namespace std;

class Complex_Calc;

class Complex
{
private:
    double m_real;
    double m_imag;

public:
    Complex(const double &arg_real = 0.0, const double &arg_imag = 0.0);
    Complex(const Complex &arg_c);
    Complex &operator=(const Complex &arg_c);
    Complex &operator+=(const Complex &arg_c);
    Complex &operator-=(const Complex &arg_c);
    Complex &operator*=(const Complex &arg_c);
    Complex &operator/=(const Complex &arg_c);
    Complex operator+(const Complex &arg_c) const
    {
        Complex res(*this);
        res += arg_c;
        return res;
    }
    Complex operator-(const Complex &arg_c) const
    {
        Complex res(*this);
        res -= arg_c;
        return res;
    }
    Complex operator*(const Complex &arg_c) const
    {
        Complex res(*this);
        res *= arg_c;
        return res;
    }
    Complex operator/(const Complex &arg_c) const
    {
        Complex res(*this);
        res /= arg_c;
        return res;
    }
    friend ostream &operator<<(ostream &arg_os, const Complex &arg_c);
    friend istream &operator>>(istream &arg_is, Complex &arg_c);
    friend class Complex_Calc;
};

Complex::Complex(const double &arg_real, const double &arg_imag)
    : m_real(arg_real), m_imag(arg_imag) {}

Complex::Complex(const Complex &arg_point)
    : m_real(arg_point.m_real), m_imag(arg_point.m_imag) {}

Complex &Complex::operator=(const Complex &arg_c)
{
    this->m_real = arg_c.m_real;
    this->m_imag = arg_c.m_imag;
    return *this;
}

Complex &Complex::operator+=(const Complex &arg_c)
{
    this->m_real += arg_c.m_real;
    this->m_imag += arg_c.m_imag;
    return *this;
}
Complex &Complex::operator-=(const Complex &arg_c)
{
    this->m_real -= arg_c.m_real;
    this->m_imag -= arg_c.m_imag;
    return *this;
}
Complex &Complex::operator*=(const Complex &arg_c)
{
    double _real = this->m_real, _imag = this->m_imag;
    this->m_real = (_real * arg_c.m_real) - (_imag * arg_c.m_imag);
    this->m_imag = (_real * arg_c.m_imag) + (_imag * arg_c.m_real);
    return *this;
}
Complex &Complex::operator/=(const Complex &arg_c)
{
    double _real = this->m_real, _imag = this->m_imag;
    this->m_real = ((_real * arg_c.m_real) + (_imag * arg_c.m_imag)) 
        / ((arg_c.m_real * arg_c.m_real + arg_c.m_imag * arg_c.m_imag));
    this->m_imag = ((-_real * arg_c.m_imag) + (_imag * arg_c.m_real)) 
        / ((arg_c.m_real * arg_c.m_real + arg_c.m_imag * arg_c.m_imag));
    return *this;
}

std::ostream &operator<<(std::ostream &arg_os, const Complex &arg_point)
{
    if (arg_point.m_imag == 0)
    {
        arg_os << arg_point.m_real;
        return arg_os;
    }
    else if (arg_point.m_imag < 0)
    {
        arg_os << arg_point.m_real << " - " << -arg_point.m_imag << "i ";
        return arg_os;
    }
    else
    {
        arg_os << arg_point.m_real << " + " << arg_point.m_imag << "i ";
        return arg_os;
    }
}

std::istream &operator>>(std::istream &arg_is, Complex &arg_point)
{
    string str_x, str_y, temp;

    if (getline(arg_is, str_x, ' '))
    {
        if (getline(arg_is, str_y, ' '))
        {
            arg_point.m_real = stod(str_x);
            arg_point.m_imag = stod(str_y);
        }
    }

    return arg_is;
}

class Complex_Calc
{
private:
    Complex m_curr_val;
    Complex m_input_val;
    char m_op, op;
    int process = 0;

    void _calc_result()
    {
        switch (m_op)
        {
        case '+':
            m_curr_val += m_input_val;
            break;
        case '-':
            m_curr_val -= m_input_val;
            break;
        case '*':
            m_curr_val *= m_input_val;
            break;
        case '/':
            if (m_input_val.m_real == 0 && m_input_val.m_imag == 0)
            {
                error_and_exit();
            }
            else
            {
                m_curr_val /= m_input_val;
                break;
            }
        case '=':
            m_curr_val = m_input_val;
            break;
        }
    }
    void _add()
    {
        m_op = '+';
    }
    void _sub()
    {
        m_op = '-';
    }
    void _mul()
    {
        m_op = '*';
    }
    void _div()
    {
        m_op = '/';
    }
    void _assign()
    {
        m_op = '=';
    }

public:
    Complex_Calc();
    Complex_Calc(const Complex_Calc &arg_int_calc);
    ~Complex_Calc(){};

    void error_and_exit();

    void set_input(const string &arg_input);

    friend ostream &operator<<(ostream &arg_os, const Complex_Calc &arg_comp_calc);
};

Complex_Calc::Complex_Calc() : m_curr_val(), m_input_val(), m_op('=')
{
}

Complex_Calc::Complex_Calc(const Complex_Calc &arg_int_calc)
    : m_curr_val(arg_int_calc.m_curr_val),
      m_input_val(arg_int_calc.m_input_val),
      m_op(arg_int_calc.m_op)
{
}

bool check_complex(const string &input)
{
    string temp_str;
    vector<string> vec;
    stringstream terms_extractor(input);
    while (terms_extractor >> temp_str)
    {
        vec.push_back(temp_str);
    }
    if (vec.size() == 2)
    {
        if ((!isdigit(vec[0][0]) && vec[0][0] != '-') 
            || (!isdigit(vec[1][0]) && vec[1][0] != '-'))
        {
            return false;
        }

        for (int i = 1; i < vec[0].size(); i++)
        {
            if (isdigit(vec[0][i]) || vec[0][i] == '.')
            {
                continue;
            }
            else
            {
                return false;
            }
        }
        for (int i = 1; i < vec[1].size(); i++)
        {
            if (isdigit(vec[1][i]) || vec[1][i] == '.')
            {
                continue;
            }
            else
            {
                return false;
            }
        }
    }
    else
    {
        return false;
    }
    return true;
}

bool check_op(const string &input)
{
    if (input == "+" || input == "-" || input == "*" || input == "/")
    {
        return true;
    }
    else
    {
        return false;
    }
}

void Complex_Calc::set_input(const string &arg_input)
{

    if ((process % 2 == 1) && (check_op(arg_input) == true))
    {
        op = arg_input[0];
    }
    else if ((process % 2 == 0) && (check_complex(arg_input) == true))
    {
        switch (op)
        {
        case '+':
            _add();
            break;
        case '-':
            _sub();
            break;
        case '*':
            _mul();
            break;
        case '/':
            _div();
            break;
        case '=':
            _assign();
            break;
        }
        stringstream ss(arg_input);
        ss >> m_input_val;
        _calc_result();
    }

    else
    {
        error_and_exit();
    }
    process = process + 1;
}

void Complex_Calc::error_and_exit()
{
    cout << "Error: Invalid input" << endl;
    exit(1);
}

std::ostream &operator<<(ostream &arg_os, const Complex_Calc &arg_comp_calc)
{
    arg_os << arg_comp_calc.m_curr_val;
    return arg_os;
}
// main function

int main()
{
    // create an instance of the class
    Complex_Calc calc;
    string input;
    while (getline(cin, input))
    {
        calc.set_input(input);
        cout << calc << endl;
    }
}

TA

#include <iostream>
#include <string>
#include <sstream>
#include <cmath>

using namespace std;

class Complex_Calc;

class Complex
{
private:
    // data members
    // save the real and imaginary parts of the complex number
    // with `double` precision
    double m_real;
    double m_imag;

public:
    // Constructor, initializes real and imaginary parts
    Complex(const double &arg_real = 0.0, const double &arg_imag = 0.0);
    // Copy constructor
    Complex(const Complex &arg_c);
    // assignment operator
    Complex &operator=(const Complex &arg_c);
    // add assignment operator
    Complex &operator+=(const Complex &arg_c);
    // subtract assignment operator
    Complex &operator-=(const Complex &arg_c);
    // multiply assignment operator
    Complex &operator*=(const Complex &arg_c);
    // divide assignment operator
    Complex &operator/=(const Complex &arg_c);
    // add function
    Complex operator+(const Complex &arg_c) const;
    // subtract function
    Complex operator-(const Complex &arg_c) const;
    // multiply function
    Complex operator*(const Complex &arg_c) const;
    // divide function
    Complex operator/(const Complex &arg_c) const;
    // cout `<<` operator for print complex number
    // note: be careful about the format of output
    friend ostream &operator<<(ostream &arg_os, const Complex &arg_c);
    // cin `>>` operator for input complex number
    // note: use `>>` to parse the string to double,
    // use `istream::fail()` to check the conversion is successful
    // and use `istream::eof()` to check the is parse to the end of line
    friend istream &operator>>(istream &arg_is, Complex &arg_c);

    friend class Complex_Calc;
};

// Complex calculator class declaration
class Complex_Calc
{
private:
    // define current value
    Complex m_curr_val;
    // define input value
    Complex m_input_val;
    // define operation
    // `+`, `-`, `*`, `/`, and `=`
    char m_op;
    // define input status, turns `op` for true and turns `value` for false
    bool m_op_input;
    // calculate result
    void _calc_result();
    // operation functions
    // set activation op to add
    void _add();
    // set activation op to subtract
    void _sub();
    // set activation op to multiply
    void _mul();
    // set activation op to divide
    void _div();
    // set activation op to assign
    void _assign();

public:
    // Constructor
    Complex_Calc();
    // Copy constructor
    Complex_Calc(const Complex_Calc &arg_int_calc);

    // Destructor
    ~Complex_Calc(){}; // no need to do anything

    // set input value or operation
    // as the same as the user input number or operation
    // into the calculator
    void set_input(const string &arg_input);

    // cout `<<` operator for print calculator status
    // note: be careful about the format of output
    friend ostream &operator<<(ostream &arg_os, const Complex_Calc &arg_comp_calc);
};

// error and exit
void error_and_exit()
{
    cerr << "Error: Invalid input" << endl;
    exit(1);
}

// Complex class implementation

// Constructor, initializes real and imaginary parts
// hint: as like as `modify` function in examples
// but use default constructor to implement
Complex::Complex(const double &arg_real, const double &arg_imag)
    : m_real(arg_real), m_imag(arg_imag)
{
}

// Copy constructor
Complex::Complex(const Complex &arg_c)
    : m_real(arg_c.m_real), m_imag(arg_c.m_imag)
{
}

// assignment operator
Complex &Complex::operator=(const Complex &arg_c)
{
    if (this == &arg_c) // self-assignment
        return *this;
    m_real = arg_c.m_real;
    m_imag = arg_c.m_imag;
    return *this;
}

// add assignment operator
Complex &Complex::operator+=(const Complex &arg_c)
{
    m_real += arg_c.m_real;
    m_imag += arg_c.m_imag;
    return *this;
}

// subtract assignment operator
Complex &Complex::operator-=(const Complex &arg_c)
{
    m_real -= arg_c.m_real;
    m_imag -= arg_c.m_imag;
    return *this;
}

// multiply assignment operator
Complex &Complex::operator*=(const Complex &arg_c)
{
    double real = m_real * arg_c.m_real - m_imag * arg_c.m_imag;
    double imag = m_real * arg_c.m_imag + m_imag * arg_c.m_real;
    m_real = real;
    m_imag = imag;
    return *this;
}

// divide assignment operator
Complex &Complex::operator/=(const Complex &arg_c)
{
    if (arg_c.m_real == 0 && arg_c.m_imag == 0)
        error_and_exit();

    double real = (m_real * arg_c.m_real + m_imag * arg_c.m_imag) 
        / (arg_c.m_real * arg_c.m_real + arg_c.m_imag * arg_c.m_imag);
    double imag = (m_imag * arg_c.m_real - m_real * arg_c.m_imag) 
        / (arg_c.m_real * arg_c.m_real + arg_c.m_imag * arg_c.m_imag);
    m_real = real;
    m_imag = imag;
    return *this;
}

// add function
Complex Complex::operator+(const Complex &arg_c) const
{
    Complex c(*this);
    c += arg_c;
    return c;
}

// subtract function
Complex Complex::operator-(const Complex &arg_c) const
{
    Complex c(*this);
    c -= arg_c;
    return c;
}

// multiply function
Complex Complex::operator*(const Complex &arg_c) const
{
    Complex c(*this);
    c *= arg_c;
    return c;
}

// divide function
Complex Complex::operator/(const Complex &arg_c) const
{
    Complex c(*this);
    c /= arg_c;
    return c;
}

// cout `<<` operator for print complex number
// note: be careful about the format of output
ostream &operator<<(ostream &arg_os, const Complex &arg_c)
{
    if (arg_c.m_imag > 0)
    {
        arg_os << arg_c.m_real << " + " << arg_c.m_imag << "i";
    }
    else if (arg_c.m_imag < 0)
    {
        arg_os << arg_c.m_real << " - " << -arg_c.m_imag << "i";
    }
    else
    {
        arg_os << arg_c.m_real;
    }
    return arg_os;
}

// cin `>>` operator for input complex number
// note: be careful about the format of input
istream &operator>>(istream &arg_is, Complex &arg_c)
{
    double input_real, input_imag;
    arg_is >> input_real;
    if (arg_is.fail())
    {
        error_and_exit();
    }
    arg_is >> input_imag;
    if (arg_is.fail() || !arg_is.eof())
    {
        error_and_exit();
    }
    arg_c.m_real = input_real;
    arg_c.m_imag = input_imag;
    return arg_is;
}

// Complex_Calc class implementation

// Constructor
Complex_Calc::Complex_Calc()
    : m_curr_val(), m_input_val(), m_op('='), m_op_input(false)
{
}

// Copy constructor
Complex_Calc::Complex_Calc(const Complex_Calc &arg_int_calc)
    : m_curr_val(arg_int_calc.m_curr_val),
      m_input_val(arg_int_calc.m_input_val),
      m_op(arg_int_calc.m_op),
      m_op_input(arg_int_calc.m_op_input)
{
}

void Complex_Calc::set_input(const string &arg_input)
{
    // input is empty, read again
    if (arg_input.empty())
        return;

    // input is a operator in right turn
    else if (m_op_input && (arg_input == "+" || arg_input == "-" 
        || arg_input == "*" || arg_input == "/" || arg_input == "="))
    {
        // set the activated operation
        // as the same as the user press the op button
        switch (arg_input[0])
        {
        case '+':
            _add();
            break;
        case '-':
            _sub();
            break;
        case '*':
            _mul();
            break;
        case '/':
            _div();
            break;
        case '=':
            _assign();
            break;
        }
        // set to 'input a complex number' turn
        m_op_input = false;
    }

    // input is a complex number in right turn
    // as the same as the user type a number
    // it performs as the same as the user pressed the '=' button
    // if the input is the first input
    // thus, we initialize the m_op to '='
    else if (!m_op_input)
    {
        stringstream ss(arg_input);
        ss >> m_input_val;
        _calc_result();
        m_op_input = true;
    }

    // else, input is invalid
    else
    {
        error_and_exit();
    }
}

void Complex_Calc::_calc_result()
{
    switch (m_op)
    {
    case '+':
        m_curr_val += m_input_val;
        break;
    case '-':
        m_curr_val -= m_input_val;
        break;
    case '*':
        m_curr_val *= m_input_val;
        break;
    case '/':
        m_curr_val /= m_input_val;
        break;
    case '=':
        m_curr_val = m_input_val;
        break;
    }
}

// add the input value to the current value
void Complex_Calc::_add()
{
    m_op = '+';
}

// subtract the input value from the current value
void Complex_Calc::_sub()
{
    m_op = '-';
}

// multiply the input value with the current value
void Complex_Calc::_mul()
{
    m_op = '*';
}

// divide the current value by the input value
void Complex_Calc::_div()
{
    m_op = '/';
}

// assign the input value to the current value
void Complex_Calc::_assign()
{
    m_op = '=';
}

// cout `<<` operator for print calculator status
ostream &operator<<(ostream &arg_os, const Complex_Calc &arg_comp_calc)
{
    arg_os << arg_comp_calc.m_curr_val;
    return arg_os;
}

// main function

int main()
{
    // create an instance of the class
    Complex_Calc calc;
    string input;
    while (getline(cin, input))
    {
        calc.set_input(input);
        cout << calc << endl;
    }
}