Java code for simple Math Expression
Here is the java code and JUnit test cases for simple math expression. The math expression can have numbers and basic operators like plus, minus, division, multiplication. Well that’s very simple to compute. However add in the parentheses into the scheme of things and it gets a little more interesting. The operator precedence and parentheses order are all taken into account. I am pretty positive that I have tested the code with some pretty weird math expressions and it came through just fine. The files in here are provided as is and anyone is free to copy it and use it to their liking.
Example Expressions:
1+1
(3.1+2.1)
(1.2+4.5)/(6*3.2+(3.4-2.1*5/2))
((((((1+1))))))
(8.1)/(9)
Java Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | /* The purpose of this program is to take a String expression with * basic math operators +*-/ and parenthesis as input * return the final result. * EX: 1+(2*3) * result: 7 */ import java.math.BigDecimal; import java.math.RoundingMode; import java.util.LinkedList; import java.util.List; import java.util.Scanner; import java.util.Stack; import java.util.regex.Matcher; import java.util.regex.Pattern; public class EvalMathString { public enum Operation { Add, Subtract, Multiply, Divide } public BigDecimal doBasicMath(BigDecimal num1, BigDecimal num2, Operation operation) { BigDecimal returnval = BigDecimal.ZERO; switch (operation) { case Add: returnval = num1.add(num2); break; case Subtract: returnval = num1.subtract(num2); break; case Multiply: returnval = num1.multiply(num2); break; case Divide: returnval = num1.divide(num2, 4, RoundingMode.HALF_UP); break; } return returnval; } public BigDecimal doMath(List<String> list) { int i = 0; BigDecimal result = BigDecimal.ZERO; Object[] strArr = list.toArray(); String temp = ""; int length = strArr.length; for (i = 0; i < length; i++) { temp = strArr[i].toString(); if (temp.equals("*") || temp.equals("/")) { BigDecimal num1 = new BigDecimal(strArr[i - 1].toString()); BigDecimal num2 = new BigDecimal(strArr[i + 1].toString()); result = doBasicMath(num1, num2,temp.equals("*") ? Operation.Multiply: Operation.Divide); strArr[i + 1] = result.toString(); strArr[i - 1] = "0"; strArr[i] = "0"; } } result = BigDecimal.ZERO; for (i = 0; i < length; i++) { String n = strArr[i].toString(); if (!n.equals("+")) { result = result.add(new BigDecimal(n)); } } return result; } public BigDecimal simpleExpression(String input) { Pattern p = Pattern.compile("(\\.\\d+)|(\\d+\\.?\\d*)"); List<String> list = new LinkedList<String>(); // input = "-1.1+2"; // input = "1.2+3.5+578.4783*23.89345*1/2-.1223"; Matcher m = p.matcher(input); int length = input.length(); int startIndex = 0; int endIndex = 0; char c = 'a'; String negative = ""; while (m.find()) { startIndex = m.start(); endIndex = m.end(); if (startIndex == 1) { negative = "-"; } if (endIndex < length) { c = input.charAt(endIndex); list.add(negative + (m.group().toString())); negative = c == '-' ? "-" : ""; if (c == '-') { list.add("+"); } else { list.add("" + c); } } else { list.add(negative + (m.group().toString())); } } /* * for(String s:list){ System.out.println(s); } */ return doMath(list); } public String performStringExpr(String input) { Stack<String> stack = new Stack<String>(); StringBuilder temp = new StringBuilder(); String ans = ""; int i = 0; int length = input.length(); char c = '0'; while(i<length){ c = input.charAt(i); if(c=='('){ stack.push(temp.toString()); temp = new StringBuilder(); }else if(c==')'){ String inpForsimpleExpr = temp.length()==0?stack.pop():temp.toString(); if(startsWithOperator(inpForsimpleExpr)){ ans = inpForsimpleExpr; }else{ ans = performStringExpr(inpForsimpleExpr); } String t = stack.pop()+ans; stack.push(t); temp = new StringBuilder(); }else{ temp.append(c); } i++; } String ele = ""; if(temp.toString().equals("")){ ele = stack.isEmpty()?"":stack.pop(); if(startsWithOperator(ele)){ String t1 = stack.pop(); stack.push(t1+ele); }else{ stack.push(ele); } } String inputforSE = stack.isEmpty()?temp.toString():stack.pop(); //Just in case the internal expressions evaluate to a -ve value and //the immediate preceding operator is + then change to - or if //the immediate preceding operator is - then change to + inputforSE = inputforSE.replaceAll("\\+-", "-"); inputforSE = inputforSE.replaceAll("--", "-"); return ""+simpleExpression(inputforSE); } private boolean startsWithOperator(String temp1) { return temp1.startsWith("*") || temp1.startsWith("+") || temp1.startsWith("/") || temp1.startsWith("-") || temp1.endsWith("*") || temp1.endsWith("/") || temp1.endsWith("+") || temp1.endsWith("-"); } public boolean validate(String input) { boolean isvalid = true; int parenCount = 0; String temp = input; temp = temp.replaceAll("[\\d\\*\\+\\(\\)-\\./]", ""); if (temp.length() > 0) { isvalid = false; } else { temp = input.replaceAll("[\\d\\*\\+-\\./]", ""); for (int i = 0; i < temp.length(); i++) { if (temp.charAt(i) == '(') { parenCount++; } else if (temp.charAt(i) == ')') { parenCount--; } } if (parenCount != 0) { isvalid = false; } } return isvalid; } public static void main(String[] args) { EvalMathString m = new EvalMathString(); System.out.println("Enter the simple Math Expression :"); Scanner n = new Scanner(System.in); String input = (n.nextLine()).replaceAll("\\s*", ""); if (m.validate(input)) { System.out.println("Expression :" + input); System.out.println("Result :" + m.performStringExpr(input)); } else { System.out.println("Invalid Input"); } } } |
JUnit Test Cases:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | import static org.junit.Assert.fail; import java.math.BigDecimal; import java.math.MathContext; import junit.framework.Assert; import org.junit.Ignore; import org.junit.Test; import com.rushi.EvalMathString; import com.rushi.EvalMathString.Operation; public class EvalMathStringTest { EvalMathString ems = new EvalMathString(); @Test public void testDoBasicMath() { Assert.assertEquals(new BigDecimal(3), ems.doBasicMath(new BigDecimal(1), new BigDecimal(2), Operation.Add)); } @Ignore public void testDoMath() { fail("Not yet implemented"); // TODO } @Test public void testSimpleExpression() { Assert.assertEquals("6.0000", ""+ems.simpleExpression("1+2*4-6/2")); } @Test public void testPerformStringExpr() { Assert.assertEquals("6.9000", ems.performStringExpr("(1+2)/2*5-(1*3/5)")); } @Test public void testPerformStringExpr1() { Assert.assertEquals("2", ems.performStringExpr("1+1")); } @Test public void testPerformStringExpr2() { Assert.assertEquals("5.2", ems.performStringExpr("(3.1+2.1)")); } @Test public void testPerformStringExpr3() { Assert.assertEquals("0.3285", ems.performStringExpr("((1.2+4.5)/(6*3.2+(3.4-2.1*5/2)))")); } @Test public void testPerformStringExpr4() { Assert.assertEquals("2", ems.performStringExpr("((((((1+1))))))")); } @Test public void testPerformStringExpr5() { Assert.assertEquals("0.9000", ems.performStringExpr("(8.1)/(9)")); } } |
Ashok
Hello,
I found your code very helpful, but I found a small bug.
// Works(Uses Order of operations).
input = “100*9+100*9”;
Above Results in 1800 which is correct.
input = “100*9+(10*10)*9”;
Above results in 1000 which is wrong.
Could you fix this? I would really appreciate it.
Thanks,
Ashok
Ashok
Solution to this is found.
input = “100*9+(10*10)*9”;
The fix is
input = “(100*9+(10*10)*9)”; // This works!
but there is another bigger problem!
input = “(12.00+9.00+3.29+(.88×4)+(2.49×2)+(.99×4)+5)”;
Above should return 41.75, but it returns 3.98.
moj
1+2*3-4/6
6.333
how can i round up to 7?