Lab 6-2: Simple Complex Number Calculator (40%)

  • 輸入:
    1. double 格式輸入複數的實數及虛數部分,以空格分開,一行輸入一個複數
    2. char 格式輸入複數的運算子,包含 +-*/,一行輸入一個運算子
    3. 複數與運算子以交錯的方式輸入,一行輸入一個複數接著一個運算子,倒數一行為複數
    4. 輸入 Ctrl+D 結束程式
    • Windows 請輸入 Ctrl+Z (會在螢幕上顯示 ^Z) 再輸入 Enter (Format 中的 ) 結束程式
  • 輸出:
    1. 顯示運算複數的結果
    2. 複數的格式為 (-)<real result> (+|-) (<imag result>i)
    3. 若輸入運算子、需顯示之前運算的結果,如 Example 的範例
  • 檔名:lab6-2_<學號>.cpp (e.g. lab6-2_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

$ ./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
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⏎
$

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: be careful about the format of input
    // hint: use `stod` to convert string to double
    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;
    // calculate result
    void _calc_result();
    // operation functions
    // add the input value to the current value
    void _add();
    // subtract the input value from the current value
    void _sub();
    // multiply the input value with the current value
    void _mul();
    // divide the current value by the input value
    void _div();
    // assign the input value to the current value
    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
    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);
};

// parse the test cases, do not modify belows

void Complex_Calc::set_input(const string &arg_input)
{
    // input is empty, read again
    if (arg_input.empty())
    {
        return;
    }
    // input is a operation
    else if (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;
        }
    }
    // 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;
        _calc_result();
    }
}

// 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:

林恩佑(109021107)

#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: be careful about the format of input
    // hint: use stod to convert string to double
    friend istream &operator>>(istream &arg_is, Complex &arg_c);

    friend class Complex_Calc;
};

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

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

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

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

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

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

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

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 << " - " << 0.0 - arg_c.m_imag << "i";
    }
    else
    {
        arg_os << arg_c.m_real << " + " << arg_c.m_imag << "i";
    }
    return arg_os;
}

istream &operator>>(istream &arg_is, Complex &arg_c)
{
    string strs;
    size_t sz;
    arg_c = {0, 0};
    arg_is >> strs;
    try
    {
        arg_c.m_real = stod(strs);
    }
    catch (const invalid_argument &ia)
    {
    }
    strs = "";
    arg_is >> strs;
    try
    {
        arg_c.m_imag = stod(strs);
    }
    catch (const invalid_argument &ia)
    {
    }
    return arg_is;
}

// 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;
    // calculate result
    void _calc_result();
    // operation functions
    // add the input value to the current value
    void _add();
    // subtract the input value from the current value
    void _sub();
    // multiply the input value with the current value
    void _mul();
    // divide the current value by the input value
    void _div();
    // assign the input value to the current value
    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
    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);
};

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)
{
}

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;
    default:
        break;
    }
}

void Complex_Calc::_add()
{
    m_op = '+';
}

void Complex_Calc::_sub()
{
    m_op = '-';
}

void Complex_Calc::_mul()
{
    m_op = '*';
}

void Complex_Calc::_div()
{
    m_op = '/';
}

void Complex_Calc::_assign()
{
    m_op = '=';
}

ostream &operator<<(ostream &arg_os, const Complex_Calc &arg_comp_calc)
{
    Complex arg_c = arg_comp_calc.m_curr_val;
    arg_os << arg_c;
    return arg_os;
}

/*
ostream &operator<<(ostream &arg_os, const Complex_Calc &arg_comp_calc){
    if (arg_c.m_imag==0){
        arg_os << arg_c.m_real <<endl;
    }
    else if (arg_c.m_imag<0){
        arg_c.m_imag*=(-1);
        arg_os<<arg_c.m_real<<" - "<<arg_c.m_imag<<" i"<<endl;
    }
    else{
        arg_os << arg_c.m_real << " + " << arg_c.m_imag <<" i"<<endl;
    }
    return arg_os;
}
*/

// parse the test cases, do not modify belows

void Complex_Calc::set_input(const string &arg_input)
{
    // input is empty, read again
    if (arg_input.empty())
    {
        return;
    }
    // input is a operation
    else if (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;
        }
    }
    // 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;
        _calc_result();
    }
}

// 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;
    arg_is >> input_imag;
    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)
{
}

// parse the test cases, do not modify belows

void Complex_Calc::set_input(const string &arg_input)
{
    // input is empty, read again
    if (arg_input.empty())
    {
        return;
    }
    // input is a operation
    else if (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;
        }
    }
    // 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;
        _calc_result();
    }
}

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;
    }
}