| | |
Simple Equation Solver ( in C++ )
Please support our C++ advertiser: Intel Parallel Studio Home
This is a remake of the Simple Equation Solver snippet that is written in Java.
This is an equivalent version written in C++.
This is an equivalent version written in C++.
/** * Numerics.cpp */ #ifndef NUMERICS #define NUMERICS #include <sstream> #include <string> using std::stringstream; using std::string; /** * Convenience class for enabling easy * conversions between strings and primitive types. * * This class is not meant to support non-primitive types, * but it should if target class Type has istream and ostream * operators overloaded. */ namespace Numerics{ template<class T> class Numerical{ private: T number; public: Numerical(T value = 0) : number(value){} Numerical(const string& arg){ const_cast<Numerical&>(*this)(arg); } /** * Attempts to assign the argument value to the value * of this Object's type. * If the value is invalid, nothing happens. */ string operator()(const string& arg){ stringstream ss (stringstream::in | stringstream::out); try{ ss << arg; ss >> number; }catch(...){ // currently unsupported } return ss.str(); } /** * Attempts to assign the argument value to the value of * this Object's type. */ T operator()(T value){ return (number = value); } /** * Returns a string representation of this Object's number */ string getString(){ stringstream ss (stringstream::in | stringstream::out); ss << number; return ss.str(); } /** * Returns a copy of this Object's number */ T getValue(){ return number; } /** * Extraction operator used to return the underlying value * during operations assosciated with primitive types. */ operator T& (){ return number; } /** * const version of the above operator. Returns a copy * of this Object's number. */ operator T () const{ return number; } }; /* Some meaningful typedefs for Numerical types */ typedef Numerical<short> Short; typedef Numerical<unsigned short> U_Short; typedef Numerical<int> Integer; typedef Numerical<unsigned int> U_Integer; typedef Numerical<double> Double; typedef Numerical<float> Float; typedef Numerical<char> Byte; typedef Numerical<unsigned char> U_Byte; typedef Numerical<wchar_t> Wide_Byte; typedef Numerical<long int> Long; typedef Numerical<unsigned long int> U_Long; /* For non-standard types, like __int8, __int16, __int32, and __int64 */ #ifdef ALLOW_NONSTANDARD_PRIMITIVE_TYPES #if (ALLOW_NONSTANDARD_PRIMITIVE_TYPES == 0x01) typedef Numerical < __int8 > __Int8; typedef Numerical < unsigned __int8 > U___Int8; typedef Numerical < __int16 > __Int16; typedef Numerical < unsigned __int16 > U___Int16; typedef Numerical < __int32 > __Int32; typedef Numerical < unsigned __int32 > U___Int32; typedef Numerical < __int64 > __Int64; typedef Numerical < unsigned __int64 > U___Int64; #endif #endif } #endif //////////////////////////////////// /** * EquationSolver.h */ #ifndef EQUATION_SOLVER_H #define EQUATION_SOLVER_H #include <string> #include <vector> using std::string; using std::vector; namespace EquationHelper{ class EquationSolver{ private: EquationSolver(); static string doOperation(const string&, char, const string&); static void correctedString(string&); static void removeSpaces(string&); static string parse(const string&); static bool isSolvable(const string&); static void calculate(vector<string>&, vector<char>&, const string&); public: static string solve(const string&, int = 50); }; } #include "EquationSolver.cpp" #endif //////////////////////////////// /** * EquationSolver.cpp */ #ifdef EQUATION_SOLVER_H #include <iostream> #include <cmath> #include <vector> #include <string> #include "Numerics.cpp" using namespace EquationHelper; using namespace Numerics; using std::size_t; using std::vector; using std::string; using std::cout; using std::endl; using std::ios; typedef EquationSolver ES; /** * Private constructor - does nothing. */ ES::EquationSolver(){} /** * Performs the specified operation against the * argument strings. The operation is dependant on * the value of op. */ string ES::doOperation(const string& lhs, char op, const string& rhs){ Double bdLhs = lhs; Double bdRhs = rhs; Double temp; switch(op){ case '^': temp( pow( bdLhs, bdRhs ) ); break; case '*': temp( bdLhs * bdRhs ); break; case '/': temp( bdLhs / bdRhs ); break; case '+': temp( bdLhs + bdRhs ); break; case '%': temp( fmod(bdLhs, bdRhs) ); break; } return temp.getString(); } /** * Returns the string with its enclosing paranthesis * stripped from it. */ void ES::correctedString(string& arg){ size_t pos1 = arg.find_first_of("("); size_t pos2 = arg.find_last_of(")"); if(pos1 >= 0 && pos1 < arg.length() && pos2 >= 0 && pos2 <= arg.length()) arg[pos1] = arg[pos2] = ' '; } /** * Remove spaces from the argument string. */ void ES::removeSpaces(string& argu){ string temp = ""; for(size_t i = 0; i < argu.length(); i++) if(argu[i] != ' ') temp += argu[i]; argu = temp; } /** * The brains of the program. * Solves expressions by using recursion for complex expressions. */ string ES::parse(const string& param){ string expression = param; correctedString(expression); removeSpaces(expression); string finalExpression = ""; bool operatorEncountered = true; for(size_t i = 0; i < expression.length(); i++){ if(expression[i] == '('){ string placeHolder = "("; int valuesCounted = 1; operatorEncountered = false; for(size_t j = i + 1; valuesCounted != 0; j++){ if(expression[j] == '(') valuesCounted++; else if(expression[j] == ')') valuesCounted--; placeHolder += expression[j]; } string evaluatedString = parse(placeHolder); finalExpression += evaluatedString; i += (placeHolder.length() - 1); }else{ if(expression[i] == '-' && operatorEncountered == false) finalExpression += '+'; finalExpression += expression[i]; if((expression[i] == '+' || expression[i] == '/' || expression[i] == '^' || expression[i] == '*' || expression[i] == '%' || expression[i] == '-')) operatorEncountered = true; else if(expression[i] != ' ') operatorEncountered = false; } } removeSpaces(finalExpression); string perfectExpression = ""; for(size_t i = 0; i < finalExpression.length(); i++){ if((i + 1) < finalExpression.length()) if(finalExpression[i] == '-' && finalExpression[i + 1] == '-') i += 2; perfectExpression += finalExpression[i]; } finalExpression = perfectExpression; vector<string> totalNumbers; vector<char> totalOperations; cout << finalExpression << endl; for(size_t i = 0; i < finalExpression.length(); i++){ if(finalExpression[i] >= '0' && finalExpression[i] <= '9' || finalExpression[i] == '-' || finalExpression[i] == '.'){ string temp = ""; // for(size_t j = i; j < finalExpression.length(); j++){ if(finalExpression[j] >= '0' && finalExpression[j] <= '9' || finalExpression[j] == '-' || finalExpression[j] == '.'){ temp += finalExpression[j]; }else break; } totalNumbers.push_back(temp); i += temp.length() == 0 ? 0 : (temp.length() - 1); }else if(finalExpression[i] == '*' || finalExpression[i] == '/' || finalExpression[i] == '^' || finalExpression[i] == '+' || finalExpression[i] == '%' ){ totalOperations.push_back(finalExpression[i]); } } ES::calculate(totalNumbers, totalOperations, "^"); ES::calculate(totalNumbers, totalOperations, "*/%"); ES::calculate(totalNumbers, totalOperations, "+"); return totalNumbers[0]; } /** * Calculates the numbers in the first vector using the operands in the 2nd vector, * based on the expressions allowed which are determined by the string argument. */ void ES::calculate(vector<string>& totalNumbers, vector<char>& totalOperations, const string& arg){ for(int i = 0; i < static_cast<int>(totalOperations.size()); i++){ if( arg.find(totalOperations[i]) != arg.npos){ totalNumbers[i] = doOperation(totalNumbers[i], totalOperations[i], totalNumbers[i + 1]); size_t oldNumberLength = totalNumbers.size(); size_t oldOperatorLength = totalOperations.size(); size_t nextNumberLength = oldNumberLength - 1; size_t nextOperatorLength = oldOperatorLength - 1; size_t sCount = 0; size_t oCount = 0; vector<string> temp1 ( nextNumberLength ); vector<char> temp2 ( nextOperatorLength ); for(size_t j = 0; j < oldNumberLength; j++){ if(j != static_cast<int>(i + 1)){ temp1[sCount++] = totalNumbers[j]; } if(j != i && j < oldOperatorLength){ temp2[oCount++] = totalOperations[j]; } } totalNumbers = temp1; totalOperations = temp2; i--; } } } /** * Returns true if the equation is solvable (not really), * returns false otherwise. * * This function is truly a misnomer, because more restrictions * should be put in place. */ bool ES::isSolvable(const string& eq){ int paranthesisCount = 0; for(size_t i = 0; i < eq.length(); i++){ if(eq[i] == '(') paranthesisCount++; else if(eq[i] == ')') paranthesisCount--; if(paranthesisCount < 0) return false; } return paranthesisCount == 0; } /** * An attempt to solve a string-expression, given * a precision value. */ string ES::solve(const string& eq, int prec){ if(isSolvable(eq)){ stringstream ss (stringstream::in | stringstream::out); cout << eq << endl; string value; value += '('; value += eq; value += ')'; ss.setf(0, ios::floatfield); ss.precision(prec); ss << parse(value); return ss.str(); }else return ""; } #endif //////////////////////////////////// /** * DriverProgram.cpp */ /**************************************** * @Author: Mark Alexander Edwards Jr. * * This program uses a utility class to solve * complex equations represented by string * expressions ****************************************/ #include <iostream> #include <ctime> #include <string> #include "Numerics.cpp" #include "EquationSolver.h" using std::cin; using std::cout; using std::endl; using std::flush; using std::string; using namespace Numerics; using namespace EquationHelper; int main(){ cout << ES::solve("5 + 3 * (8 - 4)") << endl << endl; cout << ES::solve("12 / (3 * 4) + 5") << endl << endl; while(true){ cout << "Enter an equation you would \nlike to solve (enter 'exit' to quit): " << flush; try{ string temp; getline(cin, temp); if(temp.compare("exit") == 0) exit(0); clock_t t1 = clock(); cout << "Answer: " + ES::solve(temp, 4) << endl; clock_t t2 = clock(); cout << "\nTime taken to calculate value: " << (t2-t1) << " Clock cycles" <<endl; }catch(...){ cout << "Invalid expression! Please try again!" << endl; } } cin.ignore(); cin.get(); return 0; }
0
•
•
•
•
When I have more time I might refactor the program to accept manipulators like cos, sin, tan, etc as well as SQRT but then again that can be accomplished by taking values to the .5 power @_@
0
•
•
•
•
Apparently there's a problem with the current program @_@
According to VernonDozier, Algebraic law states that exponents are evaluated in a R-to-L fashion and not L-to-R.
The fix is easy to produce, but introducing negative multiplication after exponential calculation may indeed be difficult unless I re-evaluate the entire system and determine how to conveniently change the implementation.
According to VernonDozier, Algebraic law states that exponents are evaluated in a R-to-L fashion and not L-to-R.
The fix is easy to produce, but introducing negative multiplication after exponential calculation may indeed be difficult unless I re-evaluate the entire system and determine how to conveniently change the implementation.
0
•
•
•
•
Just browsing the code I wondered why there is no case '-' in string ES::doOperation(const string& lhs, char op, const string& rhs){...
0
•
•
•
•
Subtraction is technically the same as adding a negative, so there was no need to add a subtraction operator to the doOperation method. Conversions from subtraction to adding a negative are most likely done during the expansion/compression portion of the parse method.
Similar Threads
- Code Snippet: Simple Equation Solver (Java)
- Prandtl equation solver (Python)
- Simple Quadratic Equation Solver - C++ - Do You Have Any Advices Would Like to Give? (C++)
- equation solver (Python)
- Equation Solver (Python)
| Thread Tools | Search this Thread |
api array beginner binary bitmap c++ c/c++ calculator char char* class classes coding compile compiler console conversion count data database delete desktop developer directshow dll download dynamic email encryption error file forms fstream function functions game getline google graph gui homeworkhelper iamthwee ifstream input int integer java lib linkedlist linker linux loop looping loops map math matrix memory multiple news node number numbertoword output parameter pointer problem program programming project proxy python random read recursion recursive reference return rpg sorting string strings struct template templates test text text-file tree unix url vector video visualstudio win32 windows winsock word wordfrequency wxwidgets




