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

后端 未结 7 845
广开言路
广开言路 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:22

    Here is a link to a straight-forward math expression parser (64 lines): http://javadots.blogspot.com/2008/11/arithemetic-expressions-solver-in-64.html

    Tweaking it to support your needs should not be too difficult

    0 讨论(0)
  • 2021-01-21 11:29

    Have a look at this: http://bracer.sourceforge.net It's my implementation of shunting-yard algorithm and this parser supports complex numbers.

    0 讨论(0)
  • 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<String, Complex> variables = new HashMap<>();
    
    /**
     * Processes the calls from the parser directly to a Complex value.
     */
    static class ComplexProcessor extends ExpressionParser.Processor<Complex> {
      @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<Complex> elements) {
        return elements.get(0);
      }
    
      /**
       * Creates a parser for this processor with matching operations and precedences set up.
       */
      static ExpressionParser<Complex> createParser() {
        ExpressionParser<Complex> parser = new ExpressionParser<Complex>(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<Complex> 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

    0 讨论(0)
  • 2021-01-21 11:34

    Use Apache Common Math. It is very easy to use.

    You can initialize both real+imaginary parts. You can also initialize them from a string. It supports a wide array of operations that you can do with imaginary numbers.

    Here is a example of code for doing some common operations:

    package complex;
    import static java.lang.String.format;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import org.apache.commons.math3.complex.Complex;
    import org.apache.commons.math3.complex.ComplexFormat;
    public class Do 
    {
        public static void main(String[] args) 
    {
         ComplexFormat format = new ComplexFormat();
        Complex lhs = new Complex(1.0, 3.0);
        Complex rhs = new Complex(2.0, 5.0);
    
        Complex answer = lhs.add(rhs);       // add two complex numbers
        System.out.println("Add : "+ format.format(answer));
        answer = lhs.subtract(rhs);  // subtract two complex numbers
        System.out.println("Subtract : "+ format.format(answer));
        answer = lhs.conjugate();
        System.out.println("Conjgate : "+ format.format(answer));
        double d = lhs.abs();
        System.out.println("Absolute : "+d);
        Complex first  = new Complex(1.0, 3.0);
        Complex second = new Complex(2.0, 5.0);
    
        answer = first.log();        // natural logarithm.
                System.out.println("Logarithm : "+ format.format(answer));
        answer = first.cos();        // cosine
                System.out.println("Cosine : "+ format.format(answer));
        answer = first.pow(second);  // first raised to the power of second
                System.out.println("Power : "+ format.format(answer));
    
                Complex z = new Complex(2.0,2.0);
                Complex z1 = z.reciprocal();
                System.out.println("Recipocal : "+ format.format(z1));
    
                System.out.println("Absoltue of 2+2i is "+z.abs());
                System.out.println("Argument of 2+2i is "+z.getArgument());
    
        Complex r = new Complex(6.3,9.6);
        String conj = format.format(r.conjugate());
        String reci = format.format(r.reciprocal());
    
        System.out.println("Conjugate : "+conj+" Recipocal : "+reci);
    
        //answer = lhs.abs();          // absolute value
        //answer = lhs.conjugate(rhs); // complex conjugate
    
        //make complex to string
    
        ComplexFormat format = new ComplexFormat(); // default format
        Complex c = new Complex(1.1111, 2.2222);
        String s = format.format(c); // s contains "1.11 + 2.22i"
        System.out.println(s);
    
        //make string to complex
    
        String z = "2.5+3.6i";
        Complex e = format.parse(z);
        System.out.println(e);
    
    }    
    }
    

    Another alternative is FrAid, if you want another option.

    0 讨论(0)
  • 2021-01-21 11:37

    Here's crazy solution: java has built-in JavaScript engine (I suppose you can access it from Processing). Now, you write a javascript class that works with complex numbers(copy it from here). Then, overload math operators as specified here. AFter that you can just eval this string from java. It's crazy and I'm not sure that it will work (i don't know javascript). Maybe it will make to find some simplier solution without parsing expressions.

    0 讨论(0)
  • 2021-01-21 11:44

    I would (and have, actually) manually make a parse table and use a simple LR or LALR parser to process it. At a reduction, you can perform the calculations. One advantage to this is that it is easy to modify the "language", or acceptable input.

    0 讨论(0)
提交回复
热议问题