Midterm-3: Enhanced Big Positive Real Number Calculator (20%)

  • Inputs:

    1. Input a big positive real number in decimal point format, one line for one number.
      1. digits before and after the decimal point are at most 9 digits, separated by a point character ..
    2. Input a operator, one line for one operator:
      1. +: add
      2. *: multiply
    3. The input is interleaved, one line for one number and one line for one operator after the number.
    4. Input Ctrl+D to finish the input.
      • Windows: Ctrl+Z (will show ^Z on the screen) then Enter ( in Format) to finish the input.
    5. The input is any valid string type.
  • Outputs:

    1. The calculation result
      1. The result is shown in decimal point format, with at most 18 digits before the decimal point, and 9 digits after the decimal point (rounding toward zero, truncate).
      2. If the input is an operator, the program should print the current result in the following line. The format please refer to the Example section.
      3. If the input operand or operator is invalid, the program should print the error message Error: Invalid input and terminate the program.
  • File name: midterm-3_<student_id>.cpp (e.g. midterm-3_106062802.cpp)

  • The program will not have any user prompts, only print the result.

  • The program only need to handle invalid inputs, i.e., invalid operand or operator. Other errors will be ingored.

  • Please based on main and BigReal_Calc::set_input that provided in the pseudo code to handle the input and output.

  • The program should be finished within 10 seconds. Any test cases will garuntee the program is finished within 10 seconds.

Format

<before dec 1>.<after dec 1>⏎
<result 1>
<op 1>⏎
<result 1>
<before dec 2>.<after dec 2>⏎
<result 2>
<op 2>⏎
<result 2>
...
<before dec n-1>.<after dec n-1>⏎
<result n-1>
<op n-1>⏎
<result n-1>
<before dec n>.<after dec n>⏎
<result n>
^Z⏎

Example

Normal

$ ./a.out
1.0⏎
1.000000000
^Z⏎
$ ./a.out
0.2⏎
0.200000000
^Z⏎
$ ./a.out
000000000.000000000⏎
0.000000000
^Z⏎
$ ./a.out
1.0⏎
1.000000000
+⏎
1.000000000
2.0⏎
3.000000000
+⏎
3.000000000
3.0⏎
6.000000000
*⏎
6.000000000
4.3⏎
25.800000000
^Z⏎
$ ./a.out
1.000000001⏎
1.000000001
+⏎
1.000000001
2.000000002⏎
3.000000003
^Z⏎
$ ./a.out
123456789.123456789⏎
123456789.123456789
+⏎
123456789.123456789
987654321.987654321⏎
1111111111.111111110
^Z⏎
$ ./a.out
1.000000001⏎
1.000000001
*⏎
1.000000001
2.000000002⏎
2.000000004
^Z⏎
$ ./a.out
123456789.123456789⏎
123456789.123456789
*⏎
123456789.123456789
987654321.987654321⏎
121932631356500531.347203169
^Z⏎

Exception Handling

$ ./a.out
+⏎
Error: Invalid input
$
$ ./a.out
1.0⏎
1.000000000
1.0⏎
Error: Invalid input
$
$ ./a.out
1.0⏎
1.000000000
+⏎
1.000000000
+⏎
Error: Invalid input
$
$ ./a.out
1.0 2.0⏎
Error: Invalid input
$
$ ./a.out
1234567890.0⏎
Error: Invalid input
$
$ ./a.out
0000000000.0⏎
Error: Invalid input
$
$ ./a.out
123456789.1234567890⏎
Error: Invalid input
$
$ ./a.out
 123456789.0⏎
Error: Invalid input
$
$ ./a.out
1.0⏎
1.000000000
sdafsdagret⏎
Error: Invalid input
$
$ ./a.out
sdoifjwepoirjpwoie⏎
Error: Invalid input
$
$ ./a.out
1.⏎
Error: Invalid input
$
$ ./a.out
.90⏎
Error: Invalid input
$

Reference

Pseudo Code

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

using namespace std;

class BigReal_Calc;

class BigReal
{
private:
    // data members
    // save the digits before and after the decimal point of a before_decimal number
    // with `long long` precision
    const long long m_dec_upperbound = 1000000000;
    long long m_before_decimal;
    long long m_after_decimal; // times 10^-9
    void _output_normalization();

public:
    // Constructor, initializes before_decimal and after_decimalinary parts
    // hint: as like as `modify` function in examples
    // but use default constructor to implement
    BigReal(const long long &arg_before_decimal = 0.0,
            const long long &arg_after_decimal = 0.0);
    // Copy constructor
    BigReal(const BigReal &arg_big_real);
    // assignment operator
    BigReal &operator=(const BigReal &arg_big_real);
    // add assignment operator
    BigReal &operator+=(const BigReal &arg_big_real);
    // multiply assignment operator
    BigReal &operator*=(const BigReal &arg_big_real);
    // add function
    BigReal operator+(const BigReal &arg_big_real) const;
    // multiply function
    BigReal operator*(const BigReal &arg_big_real) const;
    // cout `<<` operator for print BigReal number
    // note: be careful about the format of output
    friend ostream &operator<<(ostream &arg_os, const BigReal &arg_big_real);
    // cin `>>` operator for input BigReal number
    // note: be careful about the format of input
    // hint: use string `+=` to append digits
    friend istream &operator>>(istream &arg_is, BigReal &arg_big_real);
};

// BigReal calculator class declaration
class BigReal_Calc
{
private:
    // define current value
    BigReal m_curr_val;
    // define input value
    BigReal 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 _mul();
    // set activation op to divide
    void _assign();

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

    // Destructor
    ~BigReal_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 BigReal_Calc &arg_comp_calc);
};

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

void BigReal_Calc::set_input(const string &arg_input)
{
    if (arg_input.empty())
    {
        return;
    }
    // input is a operation
    else if ()
    {
        // set the activated operation
        // as the same as the user press the op button
        switch (arg_input[0])
        {
        case '+':
            _add();
            break;
        case '*':
            _mul();
            break;
        case '=':
            _assign();
            break;
        }
        // set to 'input a complex number' turn
        
    }
    // 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 if ()
    {
        stringstream ss(arg_input);
        ss >> m_input_val;
        _calc_result();
        // set to 'input a op' turn
        
    }
    else
    {
        error_and_exit();
    }
}

// main function

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

TA Version Code

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

using namespace std;

class BigReal_Calc;

class BigReal
{
private:
    // data members
    // save the digits before and after the decimal point of a before_decimal number
    // with `long long` precision
    const long long m_dec_upperbound = 1000000000;
    long long m_before_decimal;
    long long m_after_decimal; // times 10^-9
    void _output_normalization();

public:
    // Constructor, initializes before_decimal and after_decimalinary parts
    // hint: as like as `modify` function in examples
    // but use default constructor to implement
    BigReal(const long long &arg_before_decimal = 0.0,
            const long long &arg_after_decimal = 0.0);
    // Copy constructor
    BigReal(const BigReal &arg_big_real);
    // assignment operator
    BigReal &operator=(const BigReal &arg_big_real);
    // add assignment operator
    BigReal &operator+=(const BigReal &arg_big_real);
    // multiply assignment operator
    BigReal &operator*=(const BigReal &arg_big_real);
    // add function
    BigReal operator+(const BigReal &arg_big_real) const;
    // multiply function
    BigReal operator*(const BigReal &arg_big_real) const;
    // cout `<<` operator for print BigReal number
    // note: be careful about the format of output
    friend ostream &operator<<(ostream &arg_os, const BigReal &arg_big_real);
    // cin `>>` operator for input BigReal number
    // note: be careful about the format of input
    // hint: use string `+=` to append digits
    friend istream &operator>>(istream &arg_is, BigReal &arg_big_real);
};

// BigReal calculator class declaration
class BigReal_Calc
{
private:
    // define current value
    BigReal m_curr_val;
    // define input value
    BigReal 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 _mul();
    // set activation op to divide
    void _assign();

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

    // Destructor
    ~BigReal_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 BigReal_Calc &arg_comp_calc);
};

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

// BigReal class implementation

void BigReal::_output_normalization()
{
    if (m_after_decimal < 0)
    {
        m_before_decimal -= 1;
        m_after_decimal += m_dec_upperbound;
    }
    if (m_after_decimal > m_dec_upperbound)
    {
        m_before_decimal += m_after_decimal / m_dec_upperbound;
        m_after_decimal = m_after_decimal % m_dec_upperbound;
    }
}

// Constructor, initializes before_decimal and after_decimalinary parts
// hint: as like as `modify` function in examples
// but use default constructor to implement
BigReal::BigReal(const long long &arg_before_decimal,
                 const long long &arg_after_decimal)
    : m_before_decimal(arg_before_decimal), m_after_decimal(arg_after_decimal)
{
}
// Copy constructor
BigReal::BigReal(const BigReal &arg_big_real)
    : m_before_decimal(arg_big_real.m_before_decimal),
      m_after_decimal(arg_big_real.m_after_decimal)
{
}
// assignment operator
BigReal &BigReal::operator=(const BigReal &arg_big_real)
{
    if (this == &arg_big_real) // self-assignment
        return *this;
    m_before_decimal = arg_big_real.m_before_decimal;
    m_after_decimal = arg_big_real.m_after_decimal;
    return *this;
}
// add assignment operator
BigReal &BigReal::operator+=(const BigReal &arg_big_real)
{
    m_before_decimal += arg_big_real.m_before_decimal;
    m_after_decimal += arg_big_real.m_after_decimal;
    _output_normalization();
    return *this;
}
// multiply assignment operator
BigReal &BigReal::operator*=(const BigReal &arg_big_real)
{
    long long before_decimal = m_before_decimal * arg_big_real.m_before_decimal;
    long long after_decimal = m_after_decimal * arg_big_real.m_after_decimal / m_dec_upperbound;
    after_decimal += m_before_decimal * arg_big_real.m_after_decimal;
    after_decimal += m_after_decimal * arg_big_real.m_before_decimal;
    m_before_decimal = before_decimal;
    m_after_decimal = after_decimal;
    _output_normalization();
    return *this;
}
// add function
BigReal BigReal::operator+(const BigReal &arg_big_real) const
{
    BigReal c(*this);
    c += arg_big_real;
    return c;
}
// multiply function
BigReal BigReal::operator*(const BigReal &arg_big_real) const
{
    BigReal c(*this);
    c *= arg_big_real;
    return c;
}
// cout `<<` operator for print BigReal number
// note: be careful about the format of output
ostream &operator<<(ostream &arg_os, const BigReal &arg_big_real)
{
    arg_os << arg_big_real.m_before_decimal << '.'
           << setfill('0') << setw(9) << arg_big_real.m_after_decimal;
    return arg_os;
}
// cin `>>` operator for input BigReal number
// note: be careful about the format of input
// hint: use string `+=` to append digits
istream &operator>>(istream &arg_is, BigReal &arg_big_real)
{
    string str_before_decimal, str_after_decimal;
    getline(arg_is, str_before_decimal, '.');
    if (str_before_decimal.empty() || str_before_decimal.size() > 9)
    {
        error_and_exit();
    }
    getline(arg_is, str_after_decimal);
    if (str_after_decimal.empty() || str_after_decimal.size() > 9 || !arg_is.eof())
    {
        error_and_exit();
    }
    for (int i = 0; i < 9; i++)
    {
        if (i >= str_after_decimal.size())
        {
            str_after_decimal += '0';
        }
        else if (!isdigit(str_after_decimal[i]))
        {
            error_and_exit();
        }
    }
    stringstream ss_before_decimal(str_before_decimal);
    ss_before_decimal >> arg_big_real.m_before_decimal;
    if (ss_before_decimal.fail())
    {
        error_and_exit();
    }
    stringstream ss_after_decimal(str_after_decimal);
    ss_after_decimal >> arg_big_real.m_after_decimal;
    if (ss_after_decimal.fail())
    {
        error_and_exit();
    }
    return arg_is;
}

// BigReal_Calc class implementation

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

// Copy constructor
BigReal_Calc::BigReal_Calc(const BigReal_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)
{
}

// calculate the result
void BigReal_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;
    default:
        error_and_exit();
    }
}

// set activation op to add
void BigReal_Calc::_add()
{
    m_op = '+';
}

// set activation op to multiply
void BigReal_Calc::_mul()
{
    m_op = '*';
}

// set activation op to assign
void BigReal_Calc::_assign()
{
    m_op = '=';
}

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

void BigReal_Calc::set_input(const string &arg_input)
{
    if (arg_input.empty())
    {
        return;
    }
    // input is a operation
    else if (m_op_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 '*':
            _mul();
            break;
        case '=':
            _assign();
            break;
        }
        // set to 'input a complex number' turn
        m_op_input = false;
    }
    // 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 if (!m_op_input)
    {
        stringstream ss(arg_input);
        ss >> m_input_val;
        _calc_result();
        // set to 'input a op' turn
        m_op_input = true;
    }
    else
    {
        error_and_exit();
    }
}

// main function

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