Java 如何在算术方程中对多个指数^进行优先排序
我正在写一个解算术方程的程序。我遇到了一个问题,当一行中有多个指数语句时,程序无法正确地解决它们。例如:2^3^2,正确答案是512,但程序输出64。这是因为程序执行2^3然后执行8^2,而不是执行3^2然后执行2^9。如果您对如何修改我当前的代码有任何想法,或者有什么需要添加的,请告诉我Java 如何在算术方程中对多个指数^进行优先排序,java,math,postfix-notation,infix-notation,exponential,Java,Math,Postfix Notation,Infix Notation,Exponential,我正在写一个解算术方程的程序。我遇到了一个问题,当一行中有多个指数语句时,程序无法正确地解决它们。例如:2^3^2,正确答案是512,但程序输出64。这是因为程序执行2^3然后执行8^2,而不是执行3^2然后执行2^9。如果您对如何修改我当前的代码有任何想法,或者有什么需要添加的,请告诉我 import java.text.DecimalFormat; import java.util.EmptyStackException; import myUtil.*; public class Pos
import java.text.DecimalFormat;
import java.util.EmptyStackException;
import myUtil.*;
public class PostFixEvaluator extends Asg6
{
public static class SyntaxErrorException extends Exception
{
SyntaxErrorException(String message)
{
super(message);
}
}
private static final String operators = "+-*/^()";
private AStack<Double> operandStack;
private double evaluateOP(char op) throws Exception
{
double rightside = operandStack.pop();
double leftside = operandStack.pop();
double result = 0;
if(op == '+')
{
result = leftside + rightside;
}
else if(op == '-')
{
result = leftside - rightside;
}
else if(op == '*')
{
result = leftside * rightside;
}
else if(op == '/')
{
if(rightside == 0)
{
throw new Exception("Can not divide by 0, the equation is undefined");
}
else
{
result = leftside / rightside;
}
}
else if(op == '^')
{
result = Math.pow(leftside, rightside);
}
return result;
}
private boolean isOperator(char ch)
{
return operators.indexOf(ch) != -1;
}
public double evaluate(String exp) throws Exception
{
operandStack = new AStack<Double>();
String[] tokens = exp.split("\\s+");
try
{
for(String nextToken : tokens)
{
char firstChar = nextToken.charAt(0);
if(Character.isDigit(firstChar))
{
double value = Double.parseDouble(nextToken);
operandStack.push(value);
}
else if (isOperator(firstChar))
{
double result = evaluateOP(firstChar);
operandStack.push(result);
}
else
{
throw new Exception("Invalid character: " + firstChar);
}
}
double answer = operandStack.pop();
if(operandStack.empty())
{
return answer;
}
else
{
throw new Exception("Syntax Error: Stack should be empty");
}
}
catch(EmptyStackException ex)
{
throw new Exception("Syntax Error: The stack is empty");
}
}
}
导入java.text.DecimalFormat;
导入java.util.EmptyStackException;
导入myUtil.*;
公共类PostFixEvaluator扩展为Asg6
{
公共静态类SyntaxErrorException扩展了异常
{
SyntaxErrorException(字符串消息)
{
超级(信息);
}
}
私有静态最终字符串运算符=“+-*/^()”;
私有堆栈;
私有双evaluateOP(char op)引发异常
{
double rightside=操作数堆栈.pop();
double leftside=操作数堆栈.pop();
双结果=0;
如果(op=='+')
{
结果=左侧+右侧;
}
else if(op='-')
{
结果=左侧-右侧;
}
else if(op=='*')
{
结果=左侧*右侧;
}
else if(op=='/'))
{
如果(右侧==0)
{
抛出新异常(“不能除以0,方程未定义”);
}
其他的
{
结果=左侧/右侧;
}
}
else if(op=='^')
{
结果=Math.pow(左侧、右侧);
}
返回结果;
}
专用布尔等位运算符(char ch)
{
返回运算符。indexOf(ch)!=-1;
}
公共双重求值(字符串exp)引发异常
{
操作数堆栈=新的堆栈();
字符串[]标记=exp.split(\\s+);
尝试
{
for(字符串nextToken:tokens)
{
char firstChar=nextToken.charAt(0);
if(字符.isDigit(firstChar))
{
double value=double.parseDouble(nextToken);
操作数堆栈推送(值);
}
else if(等位符(firstChar))
{
双重结果=evaluateOP(firstChar);
操作数堆栈。推送(结果);
}
其他的
{
抛出新异常(“无效字符:+firstChar”);
}
}
双答案=操作数堆栈.pop();
if(operationStack.empty())
{
返回答案;
}
其他的
{
抛出新异常(“语法错误:堆栈应为空”);
}
}
捕获(EmptyStackException ex)
{
抛出新异常(“语法错误:堆栈为空”);
}
}
}
您正在尝试使用LL(1)语法(递归下降解析器可以解析的语法)来建模右关联运算符(^
)。右关联运算符需要左递归,这在LL(1)语法中并不容易实现。你会想看看左因子分解:我会用操作符优先级来解决这个问题,因为你可能无论如何都想要它们。
为了测试,我对类做了一些修改,这样我就可以测试它了,它肯定不是最有效或可读的,但是您应该
这就是它的工作原理
import java.text.DecimalFormat;
import java.util.EmptyStackException;
import java.util.*;
public class PostFixEvaluator
{
public static class SyntaxErrorException extends Exception
{
SyntaxErrorException(String message)
{
super(message);
}
}
private static final String operators = "+-*/^()";
private static int[] operatorPriority = {1,1,2,2,3,10,10};
private Stack<Double> operandStack;
private Stack<Character> operatorStack;
private double evaluateOP(char op) throws Exception
{
double rightside = operandStack.pop();
double leftside = operandStack.pop();
double result = 0;
if(op == '+')
{
result = leftside + rightside;
}
else if(op == '-')
{
result = leftside - rightside;
}
else if(op == '*')
{
result = leftside * rightside;
}
else if(op == '/')
{
if(rightside == 0)
{
throw new Exception("Can not divide by 0, the equation is undefined");
}
else
{
result = leftside / rightside;
}
}
else if(op == '^')
{
result = Math.pow(leftside, rightside);
}
return result;
}
private boolean isOperator(char ch)
{
return operators.indexOf(ch) != -1;
}
public double evaluate(String exp) throws Exception
{
operandStack = new Stack<Double>();
operatorStack = new Stack<Character>();
String[] tokens = exp.split("\\s+");
try
{
for(String nextToken : tokens)
{
char firstChar = nextToken.charAt(0);
if(Character.isDigit(firstChar))
{
double value = Double.parseDouble(nextToken);
operandStack.push(value);
}
else if (isOperator(firstChar))
{
// Try to evaluate the operators on the stack
while (!operatorStack.isEmpty())
{
char tmpOperator = operatorStack.pop();
// If Operator has higher Priority than the one before,
// Calculate it first if equal first calculate the second
// operator to get the ^ problem fixed
if (operatorPriority[operators.indexOf(firstChar)] >= operatorPriority[operators.indexOf(tmpOperator)])
{
operatorStack.push(tmpOperator);
// Operand has to be fetched first
break;
}
else
{
double result = evaluateOP(tmpOperator);
operandStack.push(result);
}
}
operatorStack.push(firstChar);
}
else
{
throw new Exception("Invalid character: " + firstChar);
}
}
// Here we need to calculate the operators left on the stack
while (!operatorStack.isEmpty())
{
char tmpOperator = operatorStack.pop();
// Operator Priority has to be descending,
// or the code before is wrong.
double result = evaluateOP(tmpOperator);
operandStack.push(result);
}
double answer = operandStack.pop();
if(operandStack.empty())
{
return answer;
}
else
{
throw new Exception("Syntax Error: Stack should be empty");
}
}
catch(EmptyStackException ex)
{
throw new Exception("Syntax Error: The stack is empty");
}
}
// For testing Only
public static void main(String[] args) throws Exception
{
PostFixEvaluator e = new PostFixEvaluator();
System.out.println(e.evaluate("2 ^ 3 ^ 2"));
}
}
导入java.text.DecimalFormat;
导入java.util.EmptyStackException;
导入java.util.*;
公共类后定影评估器
{
公共静态类SyntaxErrorException扩展了异常
{
SyntaxErrorException(字符串消息)
{
超级(信息);
}
}
私有静态最终字符串运算符=“+-*/^()”;
私有静态int[]运算符优先级={1,1,2,2,3,10,10};
私有堆栈;
私有堆栈操作符Stack;
私有双evaluateOP(char op)引发异常
{
double rightside=操作数堆栈.pop();
double leftside=操作数堆栈.pop();
双结果=0;
如果(op=='+')
{
结果=左侧+右侧;
}
else if(op='-')
{
结果=左侧-右侧;
}
else if(op=='*')
{
结果=左侧*右侧;
}
else if(op=='/'))
{
如果(右侧==0)
{
抛出新异常(“不能除以0,方程未定义”);
}
其他的
{
结果=左侧/右侧;
}
}
else if(op=='^')
{
结果=Math.pow(左侧、右侧);
}
返回结果;
}
专用布尔等位运算符(char ch)
{
返回运算符。indexOf(ch)!=-1;
}
公共双重求值(字符串exp)引发异常
{
操作数堆栈=新堆栈();
运算符堆栈=新堆栈();
字符串[]标记=exp.split(\\s+);
尝试
{
for(字符串nextToken:tokens)
{
char firstChar=nextToken.charAt(0);
if(字符.isDigit(firstChar))
{
double value=double.parseDouble(nextToken);
操作数堆栈推送(值);
}
else if(等位符(firstChar))
{
//尝试计算堆栈上的运算符
而(!operatorStack.isEmpty())
{
char tmpOperator=运算符stack.pop();
//如果操作员的优先级高于之前的优先级,
//先计算一下