Lab 4-3: Advance Complex Number Calculation (15%)

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

注意事項:

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

Format

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

Example

Normal

$ ./a.out
1.0 0.0⏎
^Z⏎
1 + 0 i
$
$ ./a.out
1.0 0.0⏎
+⏎
2.0 1.1⏎
-⏎
-3.0 -2.2⏎
*⏎
4.3 2.1⏎
/⏎
-1.2 -3.4⏎
^Z⏎
-8.74846 + 2.46231 i
$

Exception Handling

$ ./a.out
+⏎
Error: Invalid input
$
$ ./a.out
1.0 0.0⏎
+⏎
^Z⏎
Error: Invalid input
$
$ ./a.out
1.0 0.0⏎
1.0 0.0⏎
Error: Invalid input
$
$ ./a.out
1.0 0.0⏎
+⏎
+⏎
Error: Invalid input
$
$ ./a.out
^Z⏎
Error: Invalid input
$
$ ./a.out
1.0 2.0 3.0⏎
Error: Invalid input
$
$ ./a.out
1.0 2.0⏎
sdafsdagret⏎
Error: Invalid input
$
$ ./a.out
sdoifjwepoirjpwoie⏎
Error: Invalid input
$

Pseudo Code

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

using namespace std;

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

public:
    // Constructor, initializes real and imaginary parts
    // hint: as like as `modify` function in examples
    // but use default constructor to implement

    // print function
    // note: be careful about the format of output
    // especially the ` ` and newline (endl)
    void print();

    // add function

    // subtract function

    // multiply function

    // divide function

    // parse function
    // note: use `stringstream` and `>>` to parse the string to double
    // and use `stringstream::fail()` to check the conversion is successful

};

// parse op global function
char parse_op(const string &arg_str);

// prompt invalid input and exit
void prompt_invalid_input()
{
    cout << "Error: Invalid input" << endl;
    exit(1);
}

int main()
{
    string input;
    Complex result_complex;
    char op = ' ';                   // default op is ' '
    bool is_process_continue = true; // current process should be continued or not

    while (is_process_continue)
    {
        // get the first input
        
        // check is not end of input
        if (input.empty() || cin.eof())
        {
            prompt_invalid_input();
        }
        // check the input is a valid complex number
        
        // calculate the result
        
        // get the second input
        
        // check is end of input or not
        if (input.empty() || cin.eof())
        {
            is_process_continue = false;
        }
        // if not end of input, check the input is a valid operator
        
    }
    result_complex.print();
    return 0;
}

Reference Code:

藍珮芳(110021116)

#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;

class Complex
{
private:
    double m_real;
    double m_imag;

public:
    Complex(double arg_real = 0.0, double arg_imag = 0.0)
    {
        m_real = arg_real;
        m_imag = arg_imag;
    }
    void print()
    {
        cout << m_real << " + " << m_imag << " i\n";
    };
    Complex add(Complex &arg_c)
    {
        Complex temp;
        temp.m_real = m_real + arg_c.m_real;
        temp.m_imag = m_imag + arg_c.m_imag;
        return temp;
    };
    Complex sub(Complex &arg_c)
    {
        Complex temp;
        temp.m_real = m_real - arg_c.m_real;
        temp.m_imag = m_imag - arg_c.m_imag;
        return temp;
    };
    Complex mul(Complex &arg_c)
    {
        Complex temp;
        temp.m_real = m_real * arg_c.m_real - m_imag * arg_c.m_imag;
        temp.m_imag = m_real * arg_c.m_imag + m_imag * arg_c.m_real;
        return temp;
    };
    Complex div(Complex &arg_c)
    {
        Complex temp;
        temp.m_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);
        temp.m_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);
        return temp;
    };
};
bool check_complex(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(string &input)
{
    if (input == "+" || input == "-" || input == "*" || input == "/")
    {
        return true;
    }
    else
    {
        return false;
    }
}
int main()
{
    string input;
    Complex result_complex;
    char op = ' ';
    int process = 0;
    while (getline(cin, input))
    {
        if ((process % 2 == 1) && (check_op(input) == true))
        {
            op = input[0];
        }
        else if ((process % 2 == 0) && (check_complex(input) == true))
        {
            double real, imag;
            stringstream ss(input);
            ss >> real >> imag;
            Complex current_complex(real, imag);
            switch (op)
            {
            case '+':
                result_complex = result_complex.add(current_complex);
                break;
            case '-':
                result_complex = result_complex.sub(current_complex);
                break;
            case '*':
                result_complex = result_complex.mul(current_complex);
                break;
            case '/':
                result_complex = result_complex.div(current_complex);
                break;
            case ' ':
                result_complex = current_complex;
                break;
            default:
                cerr << "Error: unknown operation\n";
                return 1;
            }
        }
        else
        {
            cout << "Error: Invalid input" << endl;
            return 0;
        }
        process = process + 1;
    }
    if (process = 0 || process % 2 == 1)
    {
        result_complex.print();
    }
    else
    {
        cout << "Error: Invalid input" << endl;
    }
    return 0;
}

TA

#include <iostream>
#include <string>
#include <sstream>
using namespace std;

void prompt_invalid_input();

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
    // hint: as like as `modify` function in examples
    // but use default constructor to implement
    Complex(const double &arg_real = 0.0, const double &arg_imag = 0.0)
    {
        m_real = arg_real;
        m_imag = arg_imag;
    }
    // print function
    // note: be careful about the format of output
    // especially the ` ` and newline (endl)
    void print()
    {
        cout << m_real << " + " << m_imag << " i" << endl;
    }
    // add function
    Complex add(const Complex &arg_c)
    {
        Complex c;
        c.m_real = m_real + arg_c.m_real;
        c.m_imag = m_imag + arg_c.m_imag;
        return c;
    }
    // subtract function
    Complex sub(const Complex &arg_c)
    {
        Complex c;
        c.m_real = m_real - arg_c.m_real;
        c.m_imag = m_imag - arg_c.m_imag;
        return c;
    }
    // multiply function
    Complex mul(const Complex &arg_c)
    {
        Complex c;
        c.m_real = m_real * arg_c.m_real - m_imag * arg_c.m_imag;
        c.m_imag = m_real * arg_c.m_imag + m_imag * arg_c.m_real;
        return c;
    }
    // divide function
    Complex div(const Complex &arg_c)
    {
        if (arg_c.m_real == 0 && arg_c.m_imag == 0)
            prompt_invalid_input();

        Complex c;
        c.m_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);
        c.m_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);
        return c;
    }
    // parse function
    // note: use `stringstream` and `>>` to parse the string to double
    // and use `stringstream::fail()` to check the conversion is successful
    bool parse(const string &arg_str)
    {
        // Check if the number of tokens = 2
        for (int i = 0, n = 0; i < arg_str.length(); i++)
        {
            if (arg_str[i] == ' ')
                n++;
            if (n > 1 || (n == 0 && i == arg_str.length() - 1))
                return false;
        }

        stringstream ss(arg_str);
        double input_real, input_imag;

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

        ss >> input_imag;
        if (ss.fail())
        {
            return false;
        }
        m_real = input_real;
        m_imag = input_imag;
        return ss.eof();
    }
};
// parse op global function
char parse_op(const string &arg_str)
{
    switch (arg_str[0])
    {
    case '+':
    case '-':
    case '*':
    case '/':
        return arg_str[0];
    default:
        return '\0'; // invalid op
    }
}
// prompt invalid input and exit
void prompt_invalid_input()
{
    cout << "Error: Invalid input" << endl;
    exit(1);
}
int main()
{
    string input;
    Complex result_complex;
    char op = ' ';                   // default op is ' '
    bool is_process_continue = true; // current process should be continued or not
    while (is_process_continue)
    {
        // get the first input
        getline(cin, input);
        // check is not end of input
        if (input.empty() || cin.eof())
        {
            prompt_invalid_input();
        }
        // check the input is a valid complex number
        Complex input_complex;
        bool is_valid_complex = input_complex.parse(input);
        if (!is_valid_complex)
        {
            prompt_invalid_input();
        }
        // calculate the result
        switch (op)
        {
        case '+':
            result_complex = result_complex.add(input_complex);
            break;
        case '-':
            result_complex = result_complex.sub(input_complex);
            break;
        case '*':
            result_complex = result_complex.mul(input_complex);
            break;
        case '/':
            result_complex = result_complex.div(input_complex);
            break;
        case ' ':
            result_complex = input_complex;
            break;
        default:
            prompt_invalid_input();
        }
        // get the second input
        getline(cin, input);
        // check is end of input or not
        if (input.empty() || cin.eof())
        {
            is_process_continue = false;
        }
        // if not end of input, check the input is a valid operator
        else
        {
            op = parse_op(input);
            if (op == '\0')
            {
                prompt_invalid_input();
            }
        }
    }
    result_complex.print();
    return 0;
}