Taschrechner Rechnung durchführen

3xpl0r3r.exe

Mitglied
Hallo Leute vlt kann mir jmd hier helfen.
In der Schule sollen wir einen Taschenrechner programmieren mit GUI. Eigentlich alle haben einen Taschenrechner gebastelt der eine Zahl mit der nächsten Zahl verrechnet und dann mit der nächsten eingebenen Zahl verrechnet. Ich wollte ganz gerne einen Taschenrechner programmieren der alle Zahlen aufnimmt und erst am Ende verrechnet und auch mit Punkt vor Strich Beachtung nur weiß ich nicht so genau wie ich das umsetzen soll. Ich haben jetzt angefangen, dass immer wenn man ein Rechenzeichen drückt also z.B. "+" die gerade eingebene Zahl in ein Array geschrieben geschrieben wird und gleichzeitig der Operator in ein anderes Array geschrieben wird. Ich weiß nur nicht genau wie ich die Rechnung durchführen soll bzw ob meine Idee überhaupt wirklich brauchbar ist und ich kenne mich noch nicht wirklich gut in Java aus 😀.
Vielen Dank schon mal für die Hilfe.
Java:
public void plus_ActionPerformed(ActionEvent evt) {
    String s=jTextField1.getText();
    double b = Double.parseDouble(s);
    jNumberField1.setDouble(b);
    a[c]=b; // Zahl wird in double array "a" geschrieben
    c=c+1; // Sprung an nächste Stelle des Arrays
    d[g]="+"; //Operator wird in String array "d" geschrieben
    g=g+1;  // Sprung an nächste Stelle des Arrays
    jTextField1.setText("");
        
  }

Diesen Code habe ich auch entsprechend für die anderen Rechenarten.
 
Anstatt zwei Arrays kannst du besser mit einem Stack arbeiten.

Jede Eingabe wird auf den Stack geworfen. Wenn oben auf dem Stack ein "*" oder ein "/" Zeichen steht, dann berechnest du direkt das Zwischenergebnis davon und speicherst dieses wiederum auf dem Stack.

Am Ende haste dann nur noch Additionen und Substraktionen, die du dann von links nach rechts auflösen kannst.

Java:
    public static void main(String[] args) {
        Stack<String> stack = new Stack<>();

        Scanner sc = new Scanner(System.in);
        String eingabe;
        int i = 0;
        System.out.println("Operand eingeben:  ");
        while (!(eingabe = sc.next()).equals("ergebnis")) {
            System.out.println((++i % 2 == 0 ? "Operand" : "Operator") + " eingeben: ");
            if (stack.size() > 0 && stack.peek().matches("[*/]")) {
                String operator = stack.pop();
                double operand1 = Double.parseDouble(stack.pop());
                double operand2 = Double.parseDouble(eingabe);
                stack.push(operator.equals("*") ? String.valueOf(operand1 * operand2) : String.valueOf(operand1 / operand2));
            } else {
                stack.push(eingabe);
            }
        }

        System.out.println("\n\nStack: "+ stack);
        Collections.reverse(stack);
        System.out.println("\n\nStack vor Endberechnung: "+ stack);


        while(stack.size() > 1) {
            double num1 = Double.parseDouble(stack.pop());
            String operator = stack.pop();
            double num2 = Double.parseDouble(stack.pop());

           stack.push((Double.toString(operator.equals("+") ? (num1 + num2) : (num1 - num2))));
        }
        System.out.println("\n\nErgebnis: "+stack.pop());
    }


MBCrcab.png
 
Hallo nochmal. Hatte gerade mal Zeit mir das anzugucken und habe jetzt einen Code geschrieben wie ich mir das gedacht habe wie es funktionieren könnte. Wenn ich jedoch dann den Rechner ausprobiere und in dem Beispiel "+" drücke kommen in der Konsole Fehlermeldungen.
Java:
  public void plus_ActionPerformed(ActionEvent evt) {
    /*String s=jTextField1.getText();
    double b = Double.parseDouble(s);
    jNumberField1.setDouble(b);
    a[c]=b;
    c=c+1;
    d[g]="+";
    g=g+1;*/
    if(st.peek()=="*"){
      st.pop();
      double b = Double.parseDouble(st.pop());
      double h = Double.parseDouble(jTextField1.getText());
      double k=b*h;
      String bh = Double.toString(k);
      st.push(bh);
      st.push("+");
      }else if(st.peek()=="/"){
      st.pop();
      double b = Double.parseDouble(st.pop());
      double h = Double.parseDouble(jTextField1.getText());
      double k=b/h;
      String bh = Double.toString(k);
      st.push(bh);
      st.push("+");
        }
    else{
    st.push(jTextField1.getText());
    st.push("+");
      }

    jTextField1.setText("");
    jTextField1.setText(st.peek());
   
        
  }
 
ah okay danke schonmal für den Tipp 🙂
Code:
Exception in thread "AWT-EventQueue-0" java.util.EmptyStackException
    at java.base/java.util.Stack.peek(Stack.java:102)
    at ttt.plus_ActionPerformed(ttt.java:494)
    at ttt$13.actionPerformed(ttt.java:224)
    at java.desktop/javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1967)
    at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2308)
    at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:405)
    at java.desktop/javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:262)
    at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:269)
    at java.desktop/java.awt.Component.processMouseEvent(Component.java:6578)
    at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3343)
    at java.desktop/java.awt.Component.processEvent(Component.java:6343)
    at java.desktop/java.awt.Container.processEvent(Container.java:2259)
    at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:4961)
    at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2317)
    at java.desktop/java.awt.Component.dispatchEvent(Component.java:4793)
    at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4904)
    at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4539)
    at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4480)
    at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2303)
    at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2758)
    at java.desktop/java.awt.Component.dispatchEvent(Component.java:4793)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:766)
    at java.desktop/java.awt.EventQueue.access$500(EventQueue.java:97)
    at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:717)
    at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:711)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:89)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:99)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:739)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:737)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:89)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:736)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:199)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

Das wird in der Konsole ausgegeben wenn ich die entsprechende Taste drücke
 
Eine ganz andere Herangehensweise wäre, den Benutzer einen arithmetischen Ausdruck eingeben zu lassen, entweder mit den Taschenrechner-Tasten oder (vielleicht noch besser) einfach per Copy&Paste in ein Texteingabefeld, und den finalen String dann zu parsen, statt sich den Zustand des Ausdrucks in einer Datenstruktur zu halten und die Datenstruktur bei jedem Tastendruck zu pflegen.

Hierfür kannst du entweder selber einen "Recursive Descent Parser" schreiben, oder aber einen solchen aus einer sogenannten Grammatik generieren lassen. Mögliche Parsergeneratoren, die Parser aus Grammatiken für Java generieren können, sind etwa ANTLR oder JavaCC.

Hier ist z.B. eine (von mir geschriebene) attributierte JavaCC Grammatik, die die Basisoperationen +, -, *, / und ^ (Potenzierung) unterstützt und den Wert eines arithmetischen Ausdrucks ausrechnet:
Code:
options
{
  static = false;
  JDK_VERSION = "1.5";
}
PARSER_BEGIN(ArithParser)
class ArithParser {}
PARSER_END(ArithParser)
SKIP : { " " | "\r" | "\t" | "\n" }
TOKEN :
{
  < ADD_OPS : ( "+" | "-" ) >
| < MUL_OPS : ( "*" | "/" ) >
| < EXP_OPS : ( "^" ) >
| < LPAR : "(" >
| < RPAR : ")" >
| < NUMBER :
    (
      ([ "0"-"9" ])* (".")? ([ "0"-"9" ])+
    | ([ "0"-"9" ])+ (".")? ([ "0"-"9" ])*
    )
    (
      [ "e", "E" ] ([ "-", "+" ])? ([ "0"-"9" ])+
    )? >
}
double expression() :
{ double v; }
{
  v = add() { return v; }
}
double add() :
{
  Token op;
  double l, r;
}
{
  l = mul()
  (
    op = < ADD_OPS > r = mul()
    {
      if ("+".equals(op.image))
        l += r;
      else if ("-".equals(op.image))
        l -= r;
    }
  )*
  { return l; }
}
double mul() :
{
  Token op;
  double l, r;
}
{
  l = unary()
  (
    op = < MUL_OPS > r = unary()
    {
      if ("*".equals(op.image))
        l *= r;
      else if ("/".equals(op.image))
        l /= r;
    }
  )*
  { return l; }
}
double unary() :
{
  Token t;
  double v;
}
{
  t = < ADD_OPS > v = unary()
  {
    if ("-".equals(t.image))
      return -v;
    return v;
  }
|
  v = pow() { return v; }
}
double pow() :
{ double l, r; }
{
  l = primary()
  (
    LOOKAHEAD(1)
    < EXP_OPS > r = unary() { l = Math.pow(l, r); }
  )*
  { return l; }
}
double primary() :
{ double v; }
{
  v = literal() { return v; }
| < LPAR > v = expression() < RPAR > { return v; }
}
double literal() :
{
  Token t;
  double v;
}
{
  t = < NUMBER > { return Double.valueOf(t.image); }
}

Dann kannst du dir javacc als JAR Datei einmal hier runterladen und in deinem Projektverzeichnis ablegen: http://central.maven.org/maven2/net/java/dev/javacc/javacc/7.0.3/javacc-7.0.3.jar

Und dann auf der Kommandozeile folgendes ausführen, um den Parser aus der Grammatik zu generieren:

java -cp javacc-7.0.3.jar javacc ArithParser.jj

Das generiert ein paar Java-Dateien für den Parser und zusammen mit der folgenden Java-Klasse ergibt das schonmal eine funktionierende REPL ("Read-eval-print loop"):

Java:
import java.io.*;
public class REPL {
  public static void main(String[] args) throws IOException {
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    while (true) {
      System.out.print("> ");
      String line = br.readLine();
      if (line == null || line.trim().length() == 0) {
        return;
      }
      try {
        ArithParser parser = new ArithParser(new StringReader(line));
        System.out.println("= " + parser.expression());
      } catch (Exception e) {
        System.out.println("Error: " + e.getMessage());
      }
    }
  }
}

Mittlerweile ist aber wahrscheinlich ANTLR populärer, da bessere Toolunterstützung dafür existiert.
 
Zuletzt bearbeitet:

Neue Themen


Zurück
Oben