Java实现简易计算器

淡淡的烟草味﹌ 2022-04-06 03:40 401阅读 0赞

一,Calculator — 表达式解析及计算

  1. package com.test;
  2. /**
  3. * @author yangpan
  4. * @Title: sell
  5. * @Package com.citymine.kafka.kafka
  6. * @Description:
  7. * @date 2018/8/2215:52
  8. */
  9. import java.util.Collections;
  10. import java.util.Stack;
  11. /**
  12. * 算数表达式求值
  13. * 直接调用Calculator的类方法conversion()
  14. * 传入算数表达式,将返回一个浮点值结果
  15. * 如果计算过程错误,将返回一个NaN
  16. */
  17. public class Calculator {
  18. private Stack<String> postfixStack = new Stack<String>();// 后缀式栈
  19. private Stack<Character> opStack = new Stack<Character>();// 运算符栈
  20. private int[] operatPriority = new int[] { 0, 3, 2, 1, -1, 1, 0, 2 };// 运用运算符ASCII码-40做索引的运算符优先级
  21. public static double conversion(String expression) {
  22. double result = 0;
  23. Calculator cal = new Calculator();
  24. try {
  25. expression = transform(expression);
  26. result = cal.calculate(expression);
  27. } catch (Exception e) {
  28. // e.printStackTrace();
  29. // 运算错误返回NaN
  30. return 0.0 / 0.0;
  31. }
  32. // return new String().valueOf(result);
  33. return result;
  34. }
  35. /**
  36. * 将表达式中负数的符号更改
  37. *
  38. * @param expression
  39. * 例如-2+-1*(-3E-2)-(-1) 被转为 ~2+~1*(~3E~2)-(~1)
  40. * @return
  41. */
  42. private static String transform(String expression) {
  43. char[] arr = expression.toCharArray();
  44. for (int i = 0; i < arr.length; i++) {
  45. if (arr[i] == '-') {
  46. if (i == 0) {
  47. arr[i] = '~';
  48. } else {
  49. char c = arr[i - 1];
  50. if (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == 'E' || c == 'e') {
  51. arr[i] = '~';
  52. }
  53. }
  54. }
  55. }
  56. if(arr[0]=='~'||arr[1]=='('){
  57. arr[0]='-';
  58. return "0"+new String(arr);
  59. }else{
  60. return new String(arr);
  61. }
  62. }
  63. /**
  64. * 按照给定的表达式计算
  65. *
  66. * @param expression
  67. * 要计算的表达式例如:5+12*(3+5)/7
  68. * @return
  69. */
  70. public double calculate(String expression) {
  71. Stack<String> resultStack = new Stack<String>();
  72. prepare(expression);
  73. Collections.reverse(postfixStack);// 将后缀式栈反转
  74. String firstValue, secondValue, currentValue;// 参与计算的第一个值,第二个值和算术运算符
  75. while (!postfixStack.isEmpty()) {
  76. currentValue = postfixStack.pop();
  77. if (!isOperator(currentValue.charAt(0))) {// 如果不是运算符则存入操作数栈中
  78. currentValue = currentValue.replace("~", "-");
  79. resultStack.push(currentValue);
  80. } else {// 如果是运算符则从操作数栈中取两个值和该数值一起参与运算
  81. secondValue = resultStack.pop();
  82. firstValue = resultStack.pop();
  83. // 将负数标记符改为负号
  84. firstValue = firstValue.replace("~", "-");
  85. secondValue = secondValue.replace("~", "-");
  86. String tempResult = calculate(firstValue, secondValue, currentValue.charAt(0));
  87. resultStack.push(tempResult);
  88. }
  89. }
  90. return Double.valueOf(resultStack.pop());
  91. }
  92. /**
  93. * 数据准备阶段将表达式转换成为后缀式栈
  94. *
  95. * @param expression
  96. */
  97. private void prepare(String expression) {
  98. opStack.push(',');// 运算符放入栈底元素逗号,此符号优先级最低
  99. char[] arr = expression.toCharArray();
  100. int currentIndex = 0;// 当前字符的位置
  101. int count = 0;// 上次算术运算符到本次算术运算符的字符的长度便于或者之间的数值
  102. char currentOp, peekOp;// 当前操作符和栈顶操作符
  103. for (int i = 0; i < arr.length; i++) {
  104. currentOp = arr[i];
  105. if (isOperator(currentOp)) {// 如果当前字符是运算符
  106. if (count > 0) {
  107. postfixStack.push(new String(arr, currentIndex, count));// 取两个运算符之间的数字
  108. }
  109. peekOp = opStack.peek();
  110. if (currentOp == ')') {// 遇到反括号则将运算符栈中的元素移除到后缀式栈中直到遇到左括号
  111. while (opStack.peek() != '(') {
  112. postfixStack.push(String.valueOf(opStack.pop()));
  113. }
  114. opStack.pop();
  115. } else {
  116. while (currentOp != '(' && peekOp != ',' && compare(currentOp, peekOp)) {
  117. postfixStack.push(String.valueOf(opStack.pop()));
  118. peekOp = opStack.peek();
  119. }
  120. opStack.push(currentOp);
  121. }
  122. count = 0;
  123. currentIndex = i + 1;
  124. } else {
  125. count++;
  126. }
  127. }
  128. if (count > 1 || (count == 1 && !isOperator(arr[currentIndex]))) {// 最后一个字符不是括号或者其他运算符的则加入后缀式栈中
  129. postfixStack.push(new String(arr, currentIndex, count));
  130. }
  131. while (opStack.peek() != ',') {
  132. postfixStack.push(String.valueOf(opStack.pop()));// 将操作符栈中的剩余的元素添加到后缀式栈中
  133. }
  134. }
  135. /**
  136. * 判断是否为算术符号
  137. *
  138. * @param c
  139. * @return
  140. */
  141. private boolean isOperator(char c) {
  142. return c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')';
  143. }
  144. /**
  145. * 利用ASCII码-40做下标去算术符号优先级
  146. *
  147. * @param cur
  148. * @param peek
  149. * @return
  150. */
  151. public boolean compare(char cur, char peek) {// 如果是peek优先级高于cur,返回true,默认都是peek优先级要低
  152. boolean result = false;
  153. if (operatPriority[(peek) - 40] >= operatPriority[(cur) - 40]) {
  154. result = true;
  155. }
  156. return result;
  157. }
  158. /**
  159. * 按照给定的算术运算符做计算
  160. *
  161. * @param firstValue
  162. * @param secondValue
  163. * @param currentOp
  164. * @return
  165. */
  166. private String calculate(String firstValue, String secondValue, char currentOp) {
  167. String result = "";
  168. switch (currentOp) {
  169. case '+':
  170. result = String.valueOf(ArithHelper.add(firstValue, secondValue));
  171. break;
  172. case '-':
  173. result = String.valueOf(ArithHelper.sub(firstValue, secondValue));
  174. break;
  175. case '*':
  176. result = String.valueOf(ArithHelper.mul(firstValue, secondValue));
  177. break;
  178. case '/':
  179. result = String.valueOf(ArithHelper.div(firstValue, secondValue));
  180. break;
  181. }
  182. return result;
  183. }
  184. }

二,ArithHelper — 计算辅助类

  1. package com.test;
  2. /**
  3. * @Title: sell
  4. * @Package com.citymine.kafka.kafka
  5. * @Description:
  6. * @date 2018/8/2215:53
  7. */
  8. public class ArithHelper {
  9. // 默认除法运算精度
  10. private static final int DEF_DIV_SCALE = 16;
  11. // 这个类不能实例化
  12. private ArithHelper() {
  13. }
  14. /**
  15. * 提供精确的加法运算。
  16. *
  17. * @param v1 被加数
  18. * @param v2 加数
  19. * @return 两个参数的和
  20. */
  21. public static double add(double v1, double v2) {
  22. java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
  23. java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
  24. return b1.add(b2).doubleValue();
  25. }
  26. public static double add(String v1, String v2) {
  27. java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
  28. java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
  29. return b1.add(b2).doubleValue();
  30. }
  31. /**
  32. * 提供精确的减法运算。
  33. *
  34. * @param v1 被减数
  35. * @param v2 减数
  36. * @return 两个参数的差
  37. */
  38. public static double sub(double v1, double v2) {
  39. java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
  40. java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
  41. return b1.subtract(b2).doubleValue();
  42. }
  43. public static double sub(String v1, String v2) {
  44. java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
  45. java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
  46. return b1.subtract(b2).doubleValue();
  47. }
  48. /**
  49. * 提供精确的乘法运算。
  50. *
  51. * @param v1
  52. * 被乘数
  53. * @param v2
  54. * 乘数
  55. * @return 两个参数的积
  56. */
  57. public static double mul(double v1, double v2) {
  58. java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
  59. java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
  60. return b1.multiply(b2).doubleValue();
  61. }
  62. public static double mul(String v1, String v2) {
  63. java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
  64. java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
  65. return b1.multiply(b2).doubleValue();
  66. }
  67. /**
  68. * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 小数点以后10位,以后的数字四舍五入。
  69. *
  70. * @param v1
  71. * 被除数
  72. * @param v2
  73. * 除数
  74. * @return 两个参数的商
  75. */
  76. public static double div(double v1, double v2) {
  77. return div(v1, v2, DEF_DIV_SCALE);
  78. }
  79. public static double div(String v1, String v2) {
  80. java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
  81. java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
  82. return b1.divide(b2, DEF_DIV_SCALE, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
  83. }
  84. /**
  85. * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 定精度,以后的数字四舍五入。
  86. *
  87. * @param v1 被除数
  88. * @param v2 除数
  89. * @param scale 表示表示需要精确到小数点以后几位。
  90. * @return 两个参数的商
  91. */
  92. public static double div(double v1, double v2, int scale) {
  93. if (scale < 0) {
  94. throw new IllegalArgumentException("The scale must be a positive integer or zero");
  95. }
  96. java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
  97. java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
  98. return b1.divide(b2, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
  99. }
  100. /**
  101. * 提供精确的小数位四舍五入处理。
  102. *
  103. * @param v 需要四舍五入的数字
  104. * @param scale 小数点后保留几位
  105. * @return 四舍五入后的结果
  106. */
  107. public static double round(double v, int scale) {
  108. if (scale < 0) {
  109. throw new IllegalArgumentException("The scale must be a positive integer or zero");
  110. }
  111. java.math.BigDecimal b = new java.math.BigDecimal(Double.toString(v));
  112. java.math.BigDecimal one = new java.math.BigDecimal("1");
  113. return b.divide(one, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
  114. }
  115. public static double round(String v, int scale) {
  116. if (scale < 0) {
  117. throw new IllegalArgumentException("The scale must be a positive integer or zero");
  118. }
  119. java.math.BigDecimal b = new java.math.BigDecimal(v);
  120. java.math.BigDecimal one = new java.math.BigDecimal("1");
  121. return b.divide(one, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();
  122. }
  123. }

三,CalculateTest — 测试类

  1. package com.test;
  2. /**
  3. * @author pj_zhang
  4. * @create 2018-12-07 18:34
  5. **/
  6. public class CalculateTest {
  7. public static void main(String[] args) {
  8. System.out.println(Calculator.conversion("1+(2*3)"));
  9. }
  10. }

20181207183934376.png

发表评论

表情:
评论列表 (有 0 条评论,401人围观)

还没有评论,来说两句吧...

相关阅读

    相关 简易计算器 Java

    简易计算器 Java 下面是一个用Java编写的简易计算器程序。该程序可以执行基本的算术运算,包括加法、减法、乘法和除法。用户可以通过命令行输入两个操作数和运算符,程序将计算