Domanda

Sto scrivendo un programma in Processing che trasforma numeri complessi. Tuttavia, voglio avere un metodo per prendere una stringa di input e calcolare la trasformazione usando una variabile complessa. Ad esempio:

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

dove z è un numero complesso. Ora, ho esaminato JEP e alcuni esempi , ma non riesco a capire se ti permetterebbe di inserire z come variabile (e in ogni caso non è gratuito). Esiste un parser di espressioni per Java (che funziona nell'elaborazione, che utilizza una vecchia versione di Java e non ha generici) che potrei usare per fare questo?

In caso contrario, qualcuno potrebbe indicarmi le basi di come crearne uno?

È stato utile?

Soluzione

Come menzionato da PhiLo, puoi usare generici. Prova questo schizzo di elaborazione:

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

E c'è una versione non commerciale di JEP disponibile (GPL). Scaricalo qui e aggiungilo al tuo percorso di classe Processing (importalo). Dopo averlo fatto con successo, puoi usare JEP in questo modo:

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

che produce l'output (previsto): (4.0, 10.0)

Altri suggerimenti

Dai un'occhiata a questo: http://bracer.sourceforge.net È la mia implementazione del cantiere di smistamento algoritmo e questo parser supporta numeri complessi.

Se per qualche motivo hai bisogno di una maggiore flessibilità rispetto a " in scatola " parser di espressioni matematiche complesse suggerite finora (= pieno controllo sugli operatori, precedenza, costruzione dell'albero), potresti prendere in considerazione il mio parser configurabile:

https://github.com/stefanhaustein/expressionparser

Esempio di codice di valutazione diretta per il tuo 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;
  }
}

Esempio di invocazione:

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

Il parser stesso è implementato in una singola file java senza dipendenze, quindi a fini di valutazione è semplice copiarlo nel tuo progetto

Vorrei (e in realtà, in realtà) fare manualmente una tabella di analisi e utilizzare un semplice parser LR o LALR per elaborarlo. A una riduzione, è possibile eseguire i calcoli. Un vantaggio è che è facile modificare la "lingua" o un input accettabile.

Ecco la pazza soluzione: java ha un motore JavaScript incorporato (suppongo che tu possa accedervi dall'elaborazione). Ora scrivi una classe javascript che funziona con numeri complessi (copialo da qui ). Quindi, sovraccarica gli operatori matematici come specificato qui . Dopodiché puoi semplicemente valutare questa stringa da Java. È pazzesco e non sono sicuro che funzionerà (non conosco javascript). Forse riuscirà a trovare una soluzione più semplice senza analizzare le espressioni.

Ecco un link ad un semplice parser di espressioni matematiche (64 righe): http://javadots.blogspot.com/2008/11/arithemetic-expressions-solver-in-64.html

Modificarlo per supportare le tue esigenze non dovrebbe essere troppo difficile

Usa Apache Common Math . È molto facile da usare.

Puoi inizializzare entrambe le parti reali + immaginarie. Puoi anche inizializzarli da una stringa. Supporta una vasta gamma di operazioni che è possibile eseguire con numeri immaginari.

Ecco un esempio di codice per eseguire alcune operazioni comuni:

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

}    
}

Un'altra alternativa è FrAid , se vuoi un'altra opzione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top