【问题标题】:Java math expression parser that can take complex numbers as a variable?可以将复数作为变量的Java数学表达式解析器?
【发布时间】:2009-09-18 19:36:00
【问题描述】:

我正在Processing 中编写一个转换复数的程序。但是,我想要一种获取输入字符串并使用复变量计算转换的方法。例如:

1/(z+1)
(z^2)/(z/2)

其中 z 是复数。现在,我查看了 JEP 和一些 examples,但我无法确定它是否允许您实际输入 z 作为变量(并且在任何情况下它都不是免费的)。是否有用于 Java 的表达式解析器(在处理中工作,它使用旧版本的 java 并且没有泛型)我可以用来执行此操作?

如果没有,有人能告诉我如何创建一个的基础知识吗?

【问题讨论】:

  • 仅供参考,Processing 不使用“Java 的旧版本”,它适用于 Java 1.6。它可以使用 Java 1.6 库,如果您在草图中需要泛型,您可以将该部分放入 .java 文件中。
  • 怎么样?这将非常有用!我尝试了很多导入语句,但没有一个允许我这样做。我正在使用带有 Sun 最新 JDK 的 Processing IDE。

标签: java math parsing processing complex-numbers


【解决方案1】:

正如 PhiLo 所提到的,您可以使用泛型。试试这个处理草图:

import java.util.*;
java.util.List<String> list = Arrays.asList("a", "b", "c");
textFont(loadFont("UMingCN-30.vlw"));
for(int i = 0; i < list.size(); i++) {
  text(list.get(i), 5, int(i*30)+30);
}

还有一个非商业版本的 JEP (GPL) 可用。下载它here 并将其添加到您的处理类路径(导入它)。 成功后,您可以像这样使用 JEP:

void setup() {
  org.nfunk.jep.JEP parser = new org.nfunk.jep.JEP();
  parser.addComplex();
  try {
    parser.parseExpression("(1+2*i) + (3+8*i)");
    println(parser.getComplexValue());
  } catch(Exception e) {
    e.printStackTrace();
  }
}

产生(预期的)输出:(4.0, 10.0)

【讨论】:

  • 如果有 GPL 版本,他们为什么要收你 500 美元?
  • 非常感谢,它运行良好(而且泛型可以节省打字时间)。不过,我无法理解 500 美元/GPL 的差异。
  • AFAIK,JEP 最初是作为 GPL 应用程序(或其他一些开放许可证)。不久前,他们开始商业化,从那时起,一个旧(ER)版本的 JEP 托管在 Sourceforge 上。毕竟,你不能只向使用 GPL 版软件多年的人收费。
【解决方案2】:

看看这个:http://bracer.sourceforge.net这是我实现的调车场算法,这个解析器支持复数。

【讨论】:

    【解决方案3】:

    如果由于某种原因您需要比目前建议的“固定”复杂数学表达式解析器更大的灵活性(= 完全控制运算符、优先级、树构造),您可能需要考虑我的可配置解析器:

    https://github.com/stefanhaustein/expressionparser

    您的案例的直接评估代码示例:

    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;
      }
    }
    

    调用示例:

      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)"));
    

    解析器本身是在单个java file 中实现的,没有依赖关系,因此出于评估目的,它很容易复制到您自己的项目中

    【讨论】:

      【解决方案4】:

      我会(实际上已经)手动创建一个解析表并使用简单的 LR 或 LALR 解析器来处理它。在减少时,您可以执行计算。这样做的一个好处是很容易修改“语言”或可接受的输入。

      【讨论】:

        【解决方案5】:

        这是一个疯狂的解决方案:java 有内置的 JavaScript 引擎(我想你可以从 Processing 中访问它)。现在,您编写一个处理复数的 javascript 类(从 here 复制它)。然后,按照指定的here 重载数学运算符。之后你可以从 java.eval 评估这个字符串。这太疯狂了,我不确定它是否会起作用(我不知道 javascript)。也许它会在不解析表达式的情况下找到一些更简单的解决方案。

        【讨论】:

          【解决方案6】:

          这是一个直接的数学表达式解析器的链接(64 行):http://javadots.blogspot.com/2008/11/arithemetic-expressions-solver-in-64.html

          调整它以支持您的需求应该不会太困难

          【讨论】:

            【解决方案7】:

            使用Apache Common Math。它非常易于使用。

            您可以同时初始化实部和虚部。您还可以从字符串初始化它们。它支持您可以对虚数进行的各种运算。

            下面是一些常见操作的代码示例:

            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);
            
            }    
            }
            

            如果您需要其他选择,另一种选择是 FrAid

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-02-25
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多