Analizador de expresiones matemáticas de Java que puede tomar números complejos como una variable?

StackOverflow https://stackoverflow.com/questions/1446466

Pregunta

Estoy escribiendo un programa en Procesando que transforma números complejos. Sin embargo, quiero tener un método para tomar una cadena de entrada y calcular la transformación usando una variable compleja. Por ejemplo:

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

donde z es un número complejo. Ahora, he mirado JEP y algunos ejemplos , pero no puedo determinar si te permitiría ingresar z como una variable (y en cualquier caso no es gratis). ¿Existe un analizador de expresiones para Java (que funciona en el procesamiento, que usa una versión anterior de Java y no tiene genéricos) que podría usar para hacer esto?

Si no lo hay, ¿podría alguien indicarme los conceptos básicos sobre cómo crear uno?

¿Fue útil?

Solución

Como mencionó PhiLo, puede usar genéricos. Pruebe este boceto de procesamiento:

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

Y hay una versión no comercial de JEP disponible (GPL). Descárguelo aquí y agréguelo a su classpath de Procesamiento (impórtelo). Después de hacerlo con éxito, puede usar JEP de esta manera:

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

que produce la salida (esperada): (4.0, 10.0)

Otros consejos

Eche un vistazo a esto: http://bracer.sourceforge.net Es mi implementación de shunting-yard algoritmo y este analizador admite números complejos.

Si por alguna razón necesita más flexibilidad que la "enlatada" analizadores de expresiones matemáticas complejas sugeridas hasta ahora (= control total sobre operadores, precedencia, construcción de árbol), es posible que desee considerar mi analizador configurable:

https://github.com/stefanhaustein/expressionparser

Ejemplo de código de evaluación directa para su caso:

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

Ejemplo de invocación:

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

El analizador en sí se implementa en un solo archivo java sin dependencias, por lo que para fines de evaluación es simple copiarlo en su propio proyecto

Yo haría (y tendría) una tabla de análisis manual y usaría un analizador LR o LALR simple para procesarla. En una reducción, puede realizar los cálculos. Una ventaja de esto es que es fácil modificar el "idioma" o la entrada aceptable.

Aquí hay una solución loca: Java tiene un motor JavaScript incorporado (supongo que puede acceder desde Procesamiento). Ahora, escribe una clase de JavaScript que funciona con números complejos (cópielo de aquí ). Luego, sobrecargue los operadores matemáticos como se especifica aquí . DESPUÉS de que puedes evaluar esta cadena desde Java. Es una locura y no estoy seguro de que funcione (no sé javascript). Tal vez sea más fácil encontrar una solución más sencilla sin analizar expresiones.

Aquí hay un enlace a un analizador de expresiones matemáticas directo (64 líneas): http://javadots.blogspot.com/2008/11/arithemetic-expressions-solver-in-64.html

Ajustarlo para satisfacer sus necesidades no debería ser demasiado difícil

Utilice Apache Common Math . Es muy fácil de usar.

Puede inicializar ambas partes reales + imaginarias. También puede inicializarlos desde una cadena. Admite una amplia gama de operaciones que puede realizar con números imaginarios.

Aquí hay un ejemplo de código para realizar algunas operaciones comunes:

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

}    
}

Otra alternativa es FrAid , si desea otra opción.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top