View Single Post
Join Date: Jun 2008
Posts: 973
Reputation: Alex Edwards is a jewel in the rough Alex Edwards is a jewel in the rough Alex Edwards is a jewel in the rough Alex Edwards is a jewel in the rough 
Solved Threads: 107
Alex Edwards's Avatar
Alex Edwards Alex Edwards is offline Offline
Posting Shark

Where does Modulus fit in with PEMDAS?

 
0
  #1
Nov 9th, 2008
I remade an equation-solver program from Java to C++, and I plan to post it soon but I would rather not until I can determine where modulus fits in with PEMDAS.

To those who don't know, PEMDAS is the order in which mathematical expressions are to be evaluated. The order is

-Paranthesis'
-Exponents
-Mulitplication and Division (same level)
-Addition and Substraction (same level)

so if I have an expression 2 + 3 * 5, according to PEMDAS, 3 * 5 must resolve first so the expression becomes 2 + 15, and the answer afterwards is 17.

Now my problem is that I don't know where Modulus fits in with PEMDAS.

Does it have higher or lower precedence than Multiplication/Division?

8 * 9 % 5 --- what should happen first? 8 * 9 or 9 % 5?

It matters because 8 * 9 first yields 72, and 72 % 5 yields 2 (because 5 subtracts into 72 fourteen times, but cannot subtract into 2 wholly, so 2 is the remainder).

If 9%5 occurs first, 4 is the result for that minor expression and 8 * 4 is 32 so the operator precedence does indeed matter.

I've done some looking up on Google and couldn't find an article to resolve this issue.

Here's my program as it is now--

  1.  
  2. /**
  3.  * Numerics.cpp
  4.  */
  5. #ifndef NUMERICS
  6. #define NUMERICS
  7.  
  8. #include <sstream>
  9. #include <string>
  10.  
  11. using std::stringstream;
  12. using std::string;
  13.  
  14. /**
  15.  * Convenience class for enabling easy
  16.  * conversions between strings and primitive types.
  17.  *
  18.  * This class is not meant to support non-primitive types,
  19.  * but it should if target class Type has istream and ostream
  20.  * operators overloaded.
  21.  */
  22. namespace Numerics{
  23.  
  24. template<class T>
  25. class Numerical{
  26.  
  27. private:
  28. T number;
  29.  
  30. public:
  31. Numerical(T value = 0) : number(value){}
  32. Numerical(const string& arg){
  33. (*this)(arg);
  34. }
  35.  
  36. /**
  37. * Attempts to assign the argument value to the value
  38. * of this Object's type.
  39. * If the value is invalid, nothing happens.
  40. */
  41. string operator()(const string& arg){
  42. stringstream ss (stringstream::in | stringstream::out);
  43. try{
  44. ss << arg;
  45. ss >> number;
  46. }catch(...){
  47. // currently unsupported
  48. }
  49. return ss.str();
  50. }
  51.  
  52. /**
  53. * Attempts to assign the argument value to the value of
  54. * this Object's type.
  55. */
  56. T operator()(T value){
  57. return (number = value);
  58. }
  59.  
  60. /**
  61. * Returns a string representation of this Object's number
  62. */
  63. string getString(){
  64. stringstream ss (stringstream::in | stringstream::out);
  65. ss << number;
  66. return ss.str();
  67. }
  68.  
  69. /**
  70. * Returns a copy of this Object's number
  71. */
  72. T getValue(){
  73. return number;
  74. }
  75.  
  76. /**
  77. * Extraction operator used to return the underlying value
  78. * during operations assosciated with primitive types.
  79. */
  80. operator T& (){
  81. return number;
  82. }
  83.  
  84. /**
  85. * const version of the above operator. Returns a copy
  86. * of this Object's number.
  87. */
  88. operator T () const{
  89. return number;
  90. }
  91. };
  92.  
  93. /* Some meaningful typedefs for Numerical types */
  94. typedef Numerical<short> Short;
  95. typedef Numerical<unsigned short> U_Short;
  96. typedef Numerical<int> Integer;
  97. typedef Numerical<unsigned int> U_Integer;
  98. typedef Numerical<double> Double;
  99. typedef Numerical<float> Float;
  100. typedef Numerical<char> Byte;
  101. typedef Numerical<unsigned char> U_Byte;
  102. typedef Numerical<wchar_t> Wide_Byte;
  103. typedef Numerical<long int> Long;
  104. typedef Numerical<unsigned long int> U_Long;
  105.  
  106. /* For non-standard types, like __int8, __int16, __int32, and __int64 */
  107. #ifdef ALLOW_NONSTANDARD_PRIMITIVE_TYPES
  108.  
  109. #if (ALLOW_NONSTANDARD_PRIMITIVE_TYPES == 0x01)
  110. typedef Numerical < __int8 > __Int8;
  111. typedef Numerical < unsigned __int8 > U___Int8;
  112. typedef Numerical < __int16 > __Int16;
  113. typedef Numerical < unsigned __int16 > U___Int16;
  114. typedef Numerical < __int32 > __Int32;
  115. typedef Numerical < unsigned __int32 > U___Int32;
  116. typedef Numerical < __int64 > __Int64;
  117. typedef Numerical < unsigned __int64 > U___Int64;
  118. #endif
  119.  
  120. #endif
  121. }
  122.  
  123. #endif


  1.  
  2. /**
  3.  * EquationSolver.h
  4.  */
  5.  
  6. #ifndef EQUATION_SOLVER_H
  7. #define EQUATION_SOLVER_H
  8.  
  9. #include <string>
  10. #include <vector>
  11.  
  12. using std::string;
  13. using std::vector;
  14.  
  15. namespace EquationHelper{
  16.  
  17. class EquationSolver{
  18. private:
  19. EquationSolver();
  20. static string doOperation(const string&, char, const string&);
  21. static void correctedString(string&);
  22. static void removeSpaces(string&);
  23. static string parse(const string&);
  24. static bool isSolvable(const string&);
  25. static void calculate(vector<string>&, vector<char>&, const string&);
  26.  
  27. public:
  28. static string solve(const string&, int = 50);
  29. };
  30. }
  31. #include "EquationSolver.cpp"
  32.  
  33. #endif

  1.  
  2. /**
  3.  * EquationSolver.cpp
  4.  */
  5.  
  6. #ifdef EQUATION_SOLVER_H
  7.  
  8. #include <iostream>
  9. #include <cmath>
  10. #include <vector>
  11. #include "Numerics.cpp"
  12.  
  13. using namespace EquationHelper;
  14. using namespace Numerics;
  15. using std::size_t;
  16. using std::vector;
  17. using std::string;
  18. using std::cout;
  19. using std::endl;
  20. using std::ios;
  21.  
  22. typedef EquationSolver ES;
  23.  
  24. /**
  25.  * Private constructor - does nothing.
  26.  */
  27. ES::EquationSolver(){}
  28.  
  29. /**
  30.  * Performs the specified operation against the
  31.  * argument strings. The operation is dependant on
  32.  * the value of op.
  33.  */
  34. string ES::doOperation(const string& lhs, char op, const string& rhs){
  35.  
  36. Double bdLhs = lhs;
  37. Double bdRhs = rhs;
  38. Double temp;
  39. switch(op){
  40. case '^':
  41. temp( pow( bdLhs, bdRhs ) );
  42. break;
  43. case '*':
  44. temp( bdLhs * bdRhs );
  45. break;
  46. case '/':
  47. temp( bdLhs / bdRhs );
  48. break;
  49. case '+':
  50. temp( bdLhs + bdRhs );
  51. break;
  52. case '%':
  53. temp( fmod(bdLhs, bdRhs) );
  54. break;
  55. }
  56. return temp.getString();
  57. }
  58.  
  59. /**
  60.  * Returns the string with its enclosing paranthesis
  61.  * stripped from it.
  62.  */
  63. void ES::correctedString(string& arg){
  64.  
  65. size_t pos1 = arg.find_first_of("(");
  66. size_t pos2 = arg.find_last_of(")");
  67.  
  68. if(pos1 >= 0 && pos1 < arg.length() && pos2 >= 0 && pos2 <= arg.length())
  69. arg[pos1] = arg[pos2] = ' ';
  70. }
  71.  
  72. /**
  73.  * Remove spaces from the argument string.
  74.  */
  75. void ES::removeSpaces(string& argu){
  76.  
  77. string temp = "";
  78. for(size_t i = 0; i < argu.length(); i++)
  79. if(argu[i] != ' ')
  80. temp += argu[i]; // only add non-space characters to temp
  81. argu = temp;
  82. }
  83.  
  84. /**
  85.  * The brains of the program.
  86.  * Solves expressions by using recursion for complex expressions.
  87.  */
  88. string ES::parse(const string& param){
  89.  
  90. string expression = param;
  91. correctedString(expression);
  92. removeSpaces(expression); // Removes paranthesis and spaces from the String expression
  93. string finalExpression = ""; // Placeholder for the final String before values and operands are parsed
  94.  
  95. bool operatorEncountered = true; // Used to determine if the previous value encountered is an operand
  96. for(size_t i = 0; i < expression.length(); i++){ // for all of the characters in the String expression
  97. if(expression[i] == '('){ // if we encounter a left paranthesis, the value must be a nested expression
  98. string placeHolder = "("; // to prevent problems determining during boolean expression-checks
  99. int valuesCounted = 1; // i.e., when should we stop? When valuesCounted is 0?
  100. operatorEncountered = false; // because this will evaluate to be a number, we don't want to consider
  101. // this char-expression to be an operand
  102. for(size_t j = i + 1; valuesCounted != 0; j++){ // We know that i has to be "(" and we've accounted for it, so i+1 is what we'll use
  103. if(expression[j] == '(') // if we encounted a left paranthesis, increment count
  104. valuesCounted++;
  105. else if(expression[j] == ')') // else if its a left paranthesis, decrement count
  106. valuesCounted--;
  107.  
  108. placeHolder += expression[j]; // append the character to the expression
  109. }
  110.  
  111. string evaluatedString = parse(placeHolder); // recursive call - evaluate the nested expression
  112. finalExpression += evaluatedString; // append the evaluatedString to the finalExpression String
  113. i += (placeHolder.length() - 1); // the nested expression is already solved - force i to jump to non-redundant characters
  114. }else{
  115. if(expression[i] == '-' && operatorEncountered == false) // if we encountered a minus sign and we didn't encounter any operands
  116. // before it, changes the subtraction to plus a negative
  117. finalExpression += '+';
  118.  
  119. finalExpression += expression[i]; // append the character to the expression
  120. if((expression[i] == '+'
  121. || expression[i] == '/'
  122. || expression[i] == '^'
  123. || expression[i] == '*'
  124. || expression[i] == '%'
  125. || expression[i] == '-')) // if we encounter a valid operand (including minus), flag operandEncountereed to be true
  126. operatorEncountered = true;
  127. else if(expression[i] != ' ') // else if we dont encounter whitespace nor an operand, flag operand to be false
  128. operatorEncountered = false;
  129. }
  130. }
  131.  
  132. removeSpaces(finalExpression); // for safety measures, removing whitespace again
  133. string perfectExpression = ""; // I'm planning on storing a better version of the finalExpression here
  134.  
  135. for(size_t i = 0; i < finalExpression.length(); i++){ // for every character in the String finalExpression
  136. if((i + 1) < finalExpression.length()) // to prevent overshooting the array, this measure is taken
  137. if(finalExpression[i] == '-' && finalExpression[i + 1] == '-') // if there are two - chars next to each other
  138. i += 2; // ignore them.
  139. perfectExpression += finalExpression[i]; // append to the perfectExpression
  140. }
  141. finalExpression = perfectExpression; // make finalExpression point to the same address as perfectExpression
  142.  
  143. vector<string> totalNumbers; // I'm planning to use this to store Number values (as Strings)
  144. vector<char> totalOperations; // I'm planning to use this to store Operand values (as Characters)
  145. cout << finalExpression << endl; // Technically a debug, but it adds a nice touch to the program.
  146.  
  147. for(size_t i = 0; i < finalExpression.length(); i++){ // for every character in the finalExpression
  148. if(finalExpression[i] >= '0' && finalExpression[i] <= '9'
  149. || finalExpression[i] == '-' || finalExpression[i] == '.'){ // if our character is part of a number
  150. string temp = ""; //
  151. for(size_t j = i; j < finalExpression.length(); j++){ // We're technically breaking good programming practice here--
  152. // I don't intend on traversing the entire String. We're breaking
  153. // out of this loop the moment a non-numeric character is encountered
  154. if(finalExpression[j] >= '0' && finalExpression[j] <= '9'
  155. || finalExpression[j] == '-' || finalExpression[j] == '.'){
  156. temp += finalExpression[j]; // append to the temporary String
  157. }else break;
  158. }
  159. totalNumbers.push_back(temp); // add our collected number to the ArrayList
  160. i += temp.length() == 0 ? 0 : (temp.length() - 1); // we don't want to have redundancy, i.e.
  161. // if number 242 is analyzed, 242, 42 and 2 shouldn't be stored, just 242
  162. // so advance i past numbers already analyzed
  163. }else if(finalExpression[i] == '*'
  164. || finalExpression[i] == '/'
  165. || finalExpression[i] == '^'
  166. || finalExpression[i] == '+'
  167. || finalExpression[i] == '%'
  168. ){ // If we run into an operand-character, store it in the operand list
  169. totalOperations.push_back(finalExpression[i]);
  170. }
  171. }
  172.  
  173. ES::calculate(totalNumbers, totalOperations, "^");
  174. ES::calculate(totalNumbers, totalOperations, "*/%");
  175. ES::calculate(totalNumbers, totalOperations, "+");
  176.  
  177. return totalNumbers[0]; // return the value remaining in the first position of the ArrayList
  178. }
  179.  
  180. /**
  181.  * Calculates the numbers in the first vector using the operands in the 2nd vector,
  182.  * based on the expressions allowed which are determined by the string argument.
  183.  */
  184. void ES::calculate(vector<string>& totalNumbers, vector<char>& totalOperations,
  185. const string& arg){
  186.  
  187. for(int i = 0; i < static_cast<int>(totalOperations.size()); i++){
  188. if( arg.find(totalOperations[i]) != arg.npos){
  189. totalNumbers[i] = doOperation(totalNumbers[i], totalOperations[i], totalNumbers[i + 1]);
  190.  
  191. size_t oldNumberLength = totalNumbers.size();
  192. size_t oldOperatorLength = totalOperations.size();
  193. size_t nextNumberLength = oldNumberLength - 1;
  194. size_t nextOperatorLength = oldOperatorLength - 1;
  195. size_t sCount = 0;
  196. size_t oCount = 0;
  197. vector<string> temp1 ( nextNumberLength );
  198. vector<char> temp2 ( nextOperatorLength );
  199.  
  200. for(size_t j = 0; j < oldNumberLength; j++){
  201. if(j != static_cast<int>(i + 1)){
  202. temp1[sCount++] = totalNumbers[j];
  203. }
  204. if(j != i && j < oldOperatorLength){
  205. temp2[oCount++] = totalOperations[j];
  206. }
  207. }
  208. totalNumbers = temp1;
  209. totalOperations = temp2;
  210.  
  211. i--;
  212. }
  213. }
  214. }
  215.  
  216. /**
  217.  * Returns true if the equation is solvable (not really),
  218.  * returns false otherwise.
  219.  *
  220.  * This function is truly a misnomer, because more restrictions
  221.  * should be put in place.
  222.  */
  223. bool ES::isSolvable(const string& eq){
  224.  
  225. int paranthesisCount = 0; // assuming 0 paranthesis to begin with
  226. for(size_t i = 0; i < eq.length(); i++){ // for every char in the String eq
  227. if(eq[i] == '(') // if the element is a left paranthesis
  228. paranthesisCount++; // increment the paranthesisCount
  229. else if(eq[i] == ')') // else if the element is a right paranthesis
  230. paranthesisCount--; // decrement the paranthesisCount
  231.  
  232. if(paranthesisCount < 0) // if brackets aren't in correct order, return false
  233. return false;
  234. }
  235. return paranthesisCount == 0; // return true if paranthesisCount is zero, otherwise return false
  236. }
  237.  
  238. /**
  239.  * An attempt to solve a string-expression, given
  240.  * a precision value.
  241.  */
  242. string ES::solve(const string& eq, int prec){
  243.  
  244. if(isSolvable(eq)){
  245.  
  246. stringstream ss (stringstream::in | stringstream::out);
  247. cout << eq << endl; // Prints out the equation before it is parsed
  248. string value;
  249.  
  250. value += '(';
  251. value += eq;
  252. value += ')';
  253.  
  254. ss.setf(0, ios::floatfield);
  255. ss.precision(prec);
  256. ss << parse(value);
  257.  
  258. return ss.str(); // returning the final value of the expression
  259. }else return "";
  260. }
  261.  
  262. #endif

  1.  
  2. /**
  3.  * DriverProgram.cpp
  4.  */
  5.  
  6. /****************************************
  7.  * @Author: Mark Alexander Edwards Jr.
  8.  *
  9.  * This program uses a utility class to solve
  10.  * complex equations represented by string
  11.  * expressions
  12.  ****************************************/
  13. #include <iostream>
  14. #include <ctime>
  15. #include <string>
  16. #include "Numerics.cpp"
  17. #include "EquationSolver.h"
  18.  
  19. using std::cin;
  20. using std::cout;
  21. using std::endl;
  22. using std::flush;
  23. using std::string;
  24. using namespace Numerics;
  25. using namespace EquationHelper;
  26.  
  27. int main(){
  28.  
  29. cout << ES::solve("5 + 3 * (8 - 4)") << endl << endl;
  30. cout << ES::solve("12 / (3 * 4) + 5") << endl << endl;
  31.  
  32. while(true){
  33. cout << "Enter an equation you would \nlike to solve (enter 'exit' to quit): " << flush;
  34. try{
  35. string temp;
  36. getline(cin, temp);
  37. clock_t t1 = clock();
  38. if(temp.compare("exit") == 0) exit(0);
  39. cout << "Answer: " + ES::solve(temp, 4) << endl;
  40. clock_t t2 = clock();
  41. cout << "\nTime taken to calculate value: " <<
  42. (t2-t1) << " Clock cycles" <<endl;
  43. }catch(...){
  44. cout << "Invalid expression! Please try again!" << endl;
  45. }
  46. }
  47.  
  48. cin.ignore();
  49. cin.get();
  50. return 0;
  51. }
Reply With Quote