Java math expression parser that can take complex numbers as a variable?

后端 未结 7 932
广开言路
广开言路 2021-01-21 10:58

I am writing a program in Processing that transforms complex numbers. However, I want to have a method of taking an input string and calculating the transformation using a compl

7条回答
  •  遥遥无期
    2021-01-21 11:30

    If for some reason you need more flexibility than the "canned" complex math expression parsers suggested so far (= full control over operators, precedence, tree construction), you may want to consider my configurable parser:

    https://github.com/stefanhaustein/expressionparser

    Example direct evaluation code for your case:

    static HashMap variables = new HashMap<>();
    
    /**
     * Processes the calls from the parser directly to a Complex value.
     */
    static class ComplexProcessor extends ExpressionParser.Processor {
      @Override
      public Complex infixOperator(ExpressionParser.Tokenizer tokenizer, String name, Complex left, Complex right) {
        switch (name.charAt(0)) {
          case '+': return left.plus(right);
          case '-': return left.minus(right);
          case '*': return left.times(right);
          case '/': return left.divides(right);
          case '^':
            if (right.im() != 0 || right.re() == (int) right.re()) {
              return left.pow((int) right.re());
            }
            throw new RuntimeException("Only integer exponents supported by Complex.pow().");
          default:
            throw new IllegalArgumentException();
        }
      }
    
      @Override
      public Complex prefixOperator(ExpressionParser.Tokenizer tokenizer, String name, Complex argument) {
        return name.equals("-") ? new Complex(0,0).minus(argument) : argument;
      }
    
      @Override
      public Complex numberLiteral(ExpressionParser.Tokenizer tokenizer, String value) {
        return new Complex(Double.parseDouble(value), 0);
      }
    
      @Override
      public Complex identifier(ExpressionParser.Tokenizer tokenizer, String name) {
        Complex value = variables.get(name);
        if (value == null) {
          throw new IllegalArgumentException("Undeclared variable: " + name);
        }
        return value;
      }
    
      @Override
      public Complex group(ExpressionParser.Tokenizer tokenizer, String paren, List elements) {
        return elements.get(0);
      }
    
      /**
       * Creates a parser for this processor with matching operations and precedences set up.
       */
      static ExpressionParser createParser() {
        ExpressionParser parser = new ExpressionParser(new ComplexProcessor());
        parser.addCallBrackets("(", ",", ")");
        parser.addGroupBrackets("(", null, ")");
        parser.addOperators(ExpressionParser.OperatorType.INFIX_RTL, 4, "^");
        parser.addOperators(ExpressionParser.OperatorType.PREFIX, 3, "+", "-");
        // 2 Reserved for implicit multiplication
        parser.addOperators(ExpressionParser.OperatorType.INFIX, 1, "*", "/");
        parser.addOperators(ExpressionParser.OperatorType.INFIX, 0, "+", "-");
        return parser;
      }
    }
    

    Example invocation:

      variables.put("i", new Complex(0, 1));
      variables.put("z", new Complex(1, 1));
    
      ExpressionParser parser = ComplexProcessor.createParser();
      System.out.println("(z^2)/(z/2):", parser.parse("(z^2)/(z/2)"));
    

    The parser itself is implemented in a single java file without dependencies, so for evaluation purposes it's simple to copy to your own project

提交回复
热议问题