Click here to Skip to main content
15,123,118 members
Please Sign up or sign in to vote.
4.67/5 (3 votes)
See more:
Hi, I'm trying to use my limited knowledge of C++ to make a calculator that follows basic mathematical operator precedence rules and can handle large equations. I have it working for +, -, *, /, and e (exponent), but I haven't found a way to parse for partial numbers (ones using a "." to separate) and negative numbers (distinguishing negative numbers from subtraction). Can it be done the way I'm trying to do it? Are there other structures that can do the job better? (remember that I'm a beginner). Please give helpful commentary only. Thanks in advance.

Update: changed the removeSpace function as pre oldgriff's advice.

<pre>#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
#include <sstream>
#include <vector>
#include <algorithm>
#include <cctype>
#include <math.h>

using namespace std;

string removeSpace(string eq);
void colate(string eq);
double calculate(vector<string> &stor, double ttl);

int main(int argc, char *argv[])
{
    while(true)
    {
    string e = "";       
    cout << "enter equation: ";
    getline(cin, e);     
    e = removeSpace(e);           
    colate(e);    
    }
      
    system("PAUSE");
    return EXIT_SUCCESS;   
}


string removeSpace(string eq)  //removes spaces from string
{
   int i = -1;
   int j = 0;
   
      while (i != eq.length())
        {
        i++;
        if (!isspace(eq[i]))
            {
            eq[j] = eq[i];
            j++;       
            }
        }
     
   eq.resize(j);
   return eq;
}


void colate(string eq)   //stores the operators and numbers in a string vector, in order
{
    double opPos = 0;
    double numPos = 0;
    vector<string> storage;
    string storeStr;
    int i = 0;
    
    while(eq.length() >= 1)
    {  
       numPos = eq.find_first_of("1234567890");                
       opPos = eq.find_first_of("*/+-se");
       
       if (numPos < opPos)
       {
          storeStr = eq.substr(numPos, opPos-numPos);
          storage.push_back(storeStr);
          eq.erase(numPos, opPos-numPos);      
       }  
          
       if (numPos > opPos)
       {
          storeStr = eq.substr(opPos, numPos-opPos);
          storage.push_back(storeStr);
          eq.erase(opPos, numPos-opPos);      
       }             
    i++;  
    }
       
    double total =0;
    total = calculate(storage, total);  //passes the string vector to calculate function
    cout << "Total: " << total << endl; 
}
  

double calculate(vector<string> &stor, double ttl)  //finds the total of the equation
{
       double Total = ttl;      
       double num1 = 0;   
       double num2 = 0;
       int Pos = 0;      //holds the position of the current operator
       string temp = ""; 
       
       vector<string>::iterator x; 
       
       vector<string> ex;  //highest operator priority vector
       ex.push_back("e");
       
       vector<string> prim;  //next highest operator priority vector
       prim.push_back("*");
       prim.push_back("/");
       
       vector<string> sec;   //lowest operator priority vector
       sec.push_back("+");
       sec.push_back("-");
        
       while (true)
       {
          //below if-else statements set the position integer according to operator precedence         
          x = find_first_of(stor.begin(), stor.end(), ex.begin(), ex.end());
          
             if (x!=stor.end())
             {
                 Pos = find_first_of(stor.begin(), stor.end(), ex.begin(), ex.end()) - stor.begin();
             }
             else
             {
                 x = find_first_of(stor.begin(), stor.end(), prim.begin(), prim.end());
                 
                 if(x!=stor.end())
                 {   
                     Pos = find_first_of(stor.begin(), stor.end(), prim.begin(), prim.end()) - stor.begin();
                 }
                 else
                 {
                     Pos = find_first_of(stor.begin(), stor.end(), sec.begin(), sec.end()) - stor.begin();
                 }    
             }
          
          //convert the strings to the left and right of the operator to double           
          num1 = atof(stor.at(Pos-1).c_str());       
          num2 = atof(stor.at(Pos+1).c_str());
             
             //perform math based on the operator found 
             if(stor.at(Pos) == "*")
             {Total = num1 * num2;}
             if(stor.at(Pos) == "/")
             {Total = num1 / num2;}
             if(stor.at(Pos) == "+")
             {Total = num1 + num2;}
             if(stor.at(Pos) == "-")
             {Total = num1 - num2;}
             if(stor.at(Pos) == "e")
             {Total = pow(num1, num2);}
             if(stor.at(Pos) == "f")
             {Total = fmod(num1, num2);}
          
          //erases the three vector spaces occupied by the two numbers and the 
          //operator and replaces them with the new number (the total)
          stor.erase(stor.begin()+Pos-1, stor.begin()+Pos+2);
             {std::ostringstream ss;
             ss << Total;
             temp = ss.str();}
          stor.insert(stor.begin()+Pos-1, temp);
          
          //returns the total of the string if the string contains the answer
             if(stor.end()-stor.begin() <=1)
             {
                 return Total;
             }          
       }
}


Posted
Updated 15-Apr-11 11:25am
v2

You need to think about what you are doing a bit better:
while (i != eq.length())
{
    i++;
    if (isspace(eq[i]))
    {continue;}

    else
    eq[j] = eq[i];
    j++;
}
Firstly, you don't need the else: if the condition evaluates to true, then it executes the continue so the else isn't needed. Secondly, even if you did carray on after the if, the indentation implies that the else code would be both the
eq[j] = eq[i];
and the
j++;
lines - this is not the case. Thirdly, be consistent: always indent code to the proper level, it makes it easier to read:
if (isspace(eq[i]))
{continue;}
Not particularly readable, is it? :laugh:

Particularly when you are starting, always use {...} for condition execution blocks: even when they are a single statemnet - it makes it obvious and can prevent problems later, when you add code that should be executed as part of the condition.
while (i != eq.length())
{
    i++;
    if (isspace(eq[i]))
    {
        continue;
    }
    else
    {
        eq[j] = eq[i];
        j++;
    }
}
I would actually re-write this a lot more simply:
while (i != eq.length())
   {
   i++;
   if (!isSpace(eq[i]))
       {
       eq[j] = eq[i];
       j++;
       }
   }
Note that I changed the name of your function to match with the others!

I know this doesn't solve your problem, but try reflecting this though your code - it will make it more readable, which can only help!
   
Comments
Jeffrey Enzo 15-Apr-11 3:27am
   
Good answer OrginalGriff. 5 for you!
thomas struss 15-Apr-11 16:17pm
   
I did notice the else and forgot to remove it, but thanks for the rest of the improvements. I will work on keeping my code more consistently formatted.
There several equation evaluators on CodeProject. You may have a look to the source code to have some ideas.
For example this one:
String Parser and Evaluator[^]
   
Comments
thomas struss 15-Apr-11 16:17pm
   
Evaluator? WTF...no wonder I didn't find much when searching. Thanks.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900