0

I am having trouble troubleshooting and figuring out why my RPN calculator is not functioning properly. I am able to do addition, subtraction, and multiplication without issue, but I cannot compute negative or complex numbers properly. I will provide my code as well as the test cases that are failing.

/*calculator.cpp*/
#include <iostream>
#include <string>
#include <sstream>
#include "functions.h"
using std::cin, std::cout, std::endl, std::string, std::istringstream;

string string_values;
int int_values;
Stack new_stack;
double double_val;
double right;
double left;
double result;

int main() {
  // prompt user input
  cout << "Type RPN expression (end with '=')." << endl;
  cout << "> ";

  while (cin >> string_values)
  {

    if (string_values.at(0) == '.')
    {
        double_val = stod(string_values);
        push(new_stack, double_val);
    }
    else if (isdigit(string_values[0]))
    {
        double_val = stod(string_values);
        push(new_stack, double_val);
    }
    else if (string_values[0] == '=')
    {
        result = pop(new_stack);
      cout << "Ans: " << result << endl;
    }
    else 
    {
        right = pop(new_stack);
      left = pop(new_stack);
      if (string_values[0] == '+')
      {
          result = (right + left);
          push(new_stack, result);
      }
      else if (string_values[0] == '-')
      {
        result = (left - right);
        push(new_stack, result);
      }
      else if (string_values[0] == '*')
      {
        result = (right * left);
        push(new_stack, result);
      }
      else if (string_values[0] == '/')
      {
        result = (left / right);
        push(new_stack, result);
      }
      else 
      {
        cout << "[ERROR] invalid operator: " << string_values << endl;
        break;
      }
    }
  }
  
  //TODO: create a command-line interface for calculator GUI

  return 0;
}
/*functions.cpp*/
#include "functions.h"
using std::cin, std::cout, std::endl, std::ostream, std::string;

#define INFO(X)  cout << "[INFO] ("<<__FUNCTION__<<":"<<__LINE__<<") " << #X << " = " << X << endl;
#define INFO_STRUCT(X) cout << "[INFO] ("<<__FUNCTION__<<":"<<__LINE__<<") " << #X << " count = " << X.count << endl;

/**
 * ----- REQUIRED -----
 * Pushes number to top of stack. If stack is full, then resize stack's array.
 * @param   stack   Target stack.
 * @param   number  Number to push to stack.
 */
void push(Stack& stack, int number) {
  // TODO: implement push function for stack
  //INFO_STRUCT(stack);
  //INFO(number);
  if (stack.capacity == stack.count)
  {
    stack.capacity = stack.capacity * 2;
    int *new_array = new int[stack.capacity];
    for (int i = 0; i < stack.count; ++i)
    {
        new_array[i] = stack.numbers[i];
    }
    delete[] stack.numbers;
    stack.numbers = new_array;
  }
    stack.numbers[stack.count] = number;
    stack.count++;
}

/**
 * ----- REQUIRED -----
 * Pops number from top of stack. If stack is empty, return INT32_MAX.
 * @param   stack   Target stack.
 * @return          Value of popped number.
 */
int pop(Stack& stack) {
  // TODO: implement pop function for stack
    //INFO_STRUCT(stack);
  
    if (stack.count != 0)
    {
        int top_number = stack.numbers[stack.count - 1];
        stack.count--;
        return top_number;
    }

    else
      {
        return (INT32_MAX);
    }
}

/**
 * ----- OPTIONAL -----
 * Returns the number at top of stack without popping it. If stack is empty, return INT32_MAX.
 * @param   stack   Target statck.
 * @return          Number at top of stack.
 */
int peek(const Stack& stack) {
  // TODO (optional): implement peek function for stack
  INFO_STRUCT(stack);
  return 0;
}
/*functions.h*/
#ifndef STACK_H
#define STACK_H

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

/**
 * The stack data type that is initially empty and has a singleton capacity.
 */
struct Stack {
    int* numbers = new int[1] {};   // array of numbers
    int capacity    = 1;            // capacity of array
    int count       = 0;            // number of elements in array
};

/**
 * ----- REQUIRED -----
 * Pushes number to top of stack. If stack is full, then resize stack's array.
 * @param   stack   Target stack.
 * @param   number  Number to push to stack.
 */
void push(Stack& stack, int number);

/**
 * ----- REQUIRED -----
 * Pops number from top of stack. If stack is empty, return INT32_MAX.
 * @param   stack   Target stack.
 * @return          Value of popped number.
 */
int pop(Stack& stack);

/**
 * ----- OPTIONAL -----
 * Returns the number at top of stack without popping it. If stack is empty, return INT32_MAX.
 * @param   stack   Target statck.
 * @return          Number at top of stack.
 */
int peek(const Stack& stack);

#endif

Test Cases: Negative example: Input:

-5 -7 -9 * - =

My Code's Output:

Type RPN expression (end with '=').
> Ans: 2.14748e+09

Expected Output:

Type RPN expression (end with '=').
> Ans: -68

Complex Example: Input:

10 10 10 * * 59 + 1024 8 * * 9 - 1000000 - =

My Code's Output:

Type RPN expression (end with '=').
> Ans: 7.67532e+06

Expected Output:

Type RPN expression (end with '=').
> Ans: 7675319

I can see that there is an issue with the placement of the period on the complex example, but I have no idea what I am doing wrong for the negative example. Any pointers would be greatly appreciated. Thank you for your time and effort!

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • Have you tried to step through your code statement by statement in a debugger? – Some programmer dude Mar 31 '21 at 19:59
  • 1
    Might want to start with a test case like `-1 =`. You don't parse negative numbers correctly (none of the first 3 cases of your `if` block handle `-1`. It doesn't start with a `.` it doesn't start with a digit and it isn't `=`. You probably wanted to push the value `-1` onto the stack, right? Gotta fix that up. – Wyck Mar 31 '21 at 20:14
  • 1
    I tried your test case input of `10 10 10 * * 59 + 1024 8 * * 9 - 1000000 - =` and it computes the right value of 7675319, it's just that it outputs it to a stream with default formatting. Consider reading how to [prevent scientific notation](https://stackoverflow.com/questions/2335657/prevent-scientific-notation-in-ostream-when-using-with-double) with `std::fixed`. – Wyck Mar 31 '21 at 20:28
  • I would upvote because you posted all your code and test cases, expected and actual output, but I'd downvote because you didn't use your debugger. – Wyck Mar 31 '21 at 20:30
  • `-5 -7 -9 * - =` ? what does minus star mean? Or rather, what is this expression in infix notation? - perhaps your RPN is different from mine. – 500 - Internal Server Error Mar 31 '21 at 20:31
  • 1
    @500-InternalServerError: In infix notation that should be `(-5) - ((-7) * (-9))` – Ben Voigt Mar 31 '21 at 20:32
  • Note that calculators typically have separate buttons for **negative** and **subtract**. Your input doesn't have different characters, so you have an ambiguity problem. Of course you can always enter a negative number by `0 n -` to produce -n – Ben Voigt Mar 31 '21 at 20:33
  • Finally you said you don't handle complex numbers correctly (and this is true, you have no complex arithmetic implementation at all) but none of your test cases have any imaginary or complex numbers. – Ben Voigt Mar 31 '21 at 20:35
  • @BenVoigt: Yup, I get it, a bit slow there, me, sorry, I was seeing this as a snapshot of the stack before evaluation, which it is not. – 500 - Internal Server Error Mar 31 '21 at 20:38

1 Answers1

0

A fix for negative numbers would check to see if a number starts with a - and also has more characters to be made sense of (length > 1).

    else if (isdigit(string_values[0]) || string_values[0] == '-' && string_values.size() > 1)

A fix for scientific notation would be to use std::setprecision from iomanip. (See reference)

#include <iomanip>

// ...

      cout << "Ans: " << std::setprecision(std::numeric_limits<long double>::digits10 + 1) 
        << result << endl;
Wyck
  • 10,311
  • 6
  • 39
  • 60
  • Do you think there's a way to do this without using iomanip? I am only allowed to use the current includes and I can't add any more. Thank you for the suggestion! –  Mar 31 '21 at 23:25
  • You could do `printf("Ans: %.19g\n", result);` – Wyck Apr 01 '21 at 14:40