AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Term (Zeichenfolge 1+2*3) in Fließkommazahl

Ein Thema von Delphi-Narr · begonnen am 16. Sep 2009 · letzter Beitrag vom 10. Nov 2009
Antwort Antwort
Seite 4 von 5   « Erste     234 5      
Benutzerbild von SirThornberry
SirThornberry
(Moderator)

Registriert seit: 23. Sep 2003
Ort: Bockwen
12.235 Beiträge
 
Delphi 2006 Professional
 
#31

Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl

  Alt 19. Okt 2009, 21:26
Zitat von alzaimar:
Poste doch mal deinen Ansatz.
Meinst du mich? Ich meinte bei mir einen richtigen Taschenrechner zum anfassen. Also nichts selbst programmiertes. Ich fand es eben nur überflüssig erst alles im String zu speichern um danach wieder daraus zu lesen wenn man diesen Schritt auch überspringen kann. In Delphi hab ich zwar auch schon einen Parser geschrieben aber ich glaube für eine Schulaufgabe ist der zu überladen. Und wenn ich Lehrer wäre würde ich meine Zweifel haben das Schüler man eben einen Parser selbst geschrieben haben. In so einem Fall würde ich mir den in allen Einzelheiten erklären lassen um dies zu überprüfen.

Eine Schwierigkeit beim Parsen ist übrigens auch noch so etwas:
+1++2*+3

Dies ist eine gültige Operation (überall einfach nur die Vorzeichen mit angegeben).
So gut wie jeder Taschenrechner hat für das Vorzeichen eine extra Taste. Wenn man die Eingaben also sofort verarbeite, und nicht erst im nachhinein parst, hat man auch keine Probleme mit 2 aufeinanderfolgenden +, - oder sogar +- oder -+ da man dann bereits bei der Eingabe das Vorzeichen der Zahl zuordnet und sich somit die Zusatzarbeit für das korrekte Parsen spart.
Jens
Mit Source ist es wie mit Kunst - Hauptsache der Künstler versteht's
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.033 Beiträge
 
Delphi 12 Athens
 
#32

Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl

  Alt 20. Okt 2009, 00:18
Zitat:
Eine Schwierigkeit beim Parsen ist übrigens auch noch so etwas:
+1++2*+3
OK, bei einer Liveeingabe ist es schon etwas schwerer, aber auch da wäre es mit relativ geringem Aufwand lösbar.

Beim parsen eines ganzen Strings ist es dagegen auch recht einfach ... hab es schießlich auch hier in dem einfachen Code (siehe vorherige Beiträge) mit drinnen


Noar, wenn du es unbedingt als Liveeingabe haben willst ...

Hier wird übrigens die selbe Rechenfunktion genutzt, welche auch in Beitrag #28 drin ist,
nur mit einem Unterschied:
Delphi-Quellcode:
Finally
  Result := '';
  For i := 0 to SL.Count - 1 do Begin
    If TryStrToFloat(SL[i], a) Then SL[i] := FloatToStr(a);
    Result := Result + SL[i] + ' ';
  End;
  Result := Trim(Result);
Beim Zusammensetzen, werden eventuell noch nicht bearbeitete Zahlen "normalisiert" und es werden Leerzeichen eingefügt.


Ansonsten wird in dem Programm sozusagen einfach nur der eigegebene Befehl/Zeichen hinten an den Text drangehängt und alles gearst.


Achtung, es sind auch Fehleingaben möglich, welche man aber auch praktisch ausnutzen kann (wie mir grad so in den Sinn kam), denn es werden ja alle möglichen Unterteile dennoch so weit wie möglich aufgelöst.

z.B. kann man sowas eingeben "8 / / 8" ... dieses doppelte "//" wird natürlich nicht aufgelößt,
so kann man jetzt etwas berechnen, macht dann einfach "//" ,
der alte Wert bleibt vorne erhalten und man kann hinten weiterrechnen.

z.B. einfach mal dieses eingeben "3 + 5 / / 2 * 4 ="

oder wie wäre es damit ... einfach mal über Strg+C in das Programm reinkopieren
Zitat:
C 3 + 5 / / 2 * 4 / / 12 * 5 + (8 + 88 * 456) * 5 / 3 =
[info]
was mir grad noch auffiehl ist, daß beim letzen Beispiel das z.B. "8 + 88" vor "88 * 456" berechnet wird, da der String direkt im Edit verwaltet und dort schon aufgelöst wurde

er rechnet praktisch so
Zitat:
C 3 + 5 / / 2 * 4 / / (12 * 5 + ((8 + 88) * 456)) * 5 / 3 =
hab aber jetzt nicht die Zeit da jetzt was zu ändern
- entweder intern den die ganze Formel merken und nur das ausgerechnete anzeigen
- oder (was wohl schöner zum Editieren ist) das "+" dort nicht auflösen, da die zugehörige "88" stärker an das "*" gebunden ist.


PS: gibt es eigentlich ein "Standardevent" für Einfügen (Strg+C)?
aktuell sieht es so aus
Delphi-Quellcode:
Procedure TForm1.EditKeyPress(Sender: TObject; Var Key: Char);
  If Key = #22 Then
und bei mir funktioniert es, aber ich weiß nicht, ob es bei allen auch noch so geht.
Angehängte Dateien
Dateityp: exe tachenrechner_672.exe (400,5 KB, 3x aufgerufen)
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#33

Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl

  Alt 20. Okt 2009, 07:08
Zitat von himitsu:
OK, bei einer Liveeingabe ist es schon etwas schwerer, aber auch da wäre es mit relativ geringem Aufwand lösbar.
Wie würdest Du die Cursortasten bzw. 'Backspace' umsetzen?

Nee, im Ernst: Mit meiner Schleife geht das eins-fix-drei, denn man muss ja nur die beiden Stacks 'global', d.h. als private Felder in eine Klasse packen und dem Evaluator eine 'ProcessChar'-Methode spendieren, die ja nur aus dem Schleifenrumpf besteht. Et voilá: Fertig ist der Live-Rechn-o-mat.
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.033 Beiträge
 
Delphi 12 Athens
 
#34

Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl

  Alt 20. Okt 2009, 10:02
nja, ich hab das ja jetzt erstmal einfach als 'normales' Edit gelöst und da löscht Backspace (in der hochgeladenen Version das letzte Zeichen und alle neuen Zeichen werden hinten angehängt ... und ich meiner internen alktuellen Version wird dieses alles jeweils an der Cursorposition gemacht und dieses (also mitten drinnen was editieren) würde garnicht gehn, wenn man es direkt in den Stack schiebt.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von Delphi-Narr
Delphi-Narr

Registriert seit: 29. Aug 2009
Ort: Duisburg
437 Beiträge
 
Delphi 2007 Professional
 
#35

Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl

  Alt 20. Okt 2009, 15:08
Zitat von alzaimar:
Zitat von himitsu:
[add]
ohne die StrUtils könnte man statt
AnsiMatchText(SL[i - 1], ['*', '/', '+', '-']) einfach dieses machen
((SL[i - 1] = '*') or (SL[i - 1] = '/') or (SL[i - 1] = '+') or (SL[i - 1] = '-'))
Oder
SL[i-1] in ['*','/','+','-'] oder
Pos('*/+-',SL[i-1])<>0

Dein Code kann aber keine Klammern, oder?
Ich hab hier was, was zusammengefrickelt ist und auch '2*+2' akzeptiert, glaube ich. Dafür kommt es mit Klammern klar und rechnet alles in einem Abwasch aus:
Delphi-Quellcode:
function Eval(term: string): Integer;
const
  isNone = 0;
  isNum = 1;
  isOp = 2;

var

**** DER CODE FUNKTIONIERT NICHT RICHTIG

  numStack: array[0..10] of Integer;
  Oporder: array[char] of Byte;
  SP: Integer;
  Ops: string;
  c: Char;
  code, sign, number: Integer;


begin
  fillchar(numstack, sizeof(numstack), 0);
  fillchar(OpOrder, sizeof(opOrder), 0);
  opOrder['+'] := 1;
  opOrder['-'] := 1;
  opOrder['*'] := 2;
  opOrder['/'] := 2;
  opOrder['('] := 99;

  sign := 1;
  Ops := '(';
  SP := 0;
  number := 0;
  Result := 0;
  term := term + ')';
  code := isNone;
  for c in term do
    case c of
      '0'..'9': begin
          number := 10 * number + ord(c) - 48;
          code := isNum;
        end;
      '+', '-', '*', '/', '(', ')': begin
          if code = isNum then begin
            numStack[SP] := sign * number;
            sign := 1;
            inc(SP);
            code := isNone;
            number := 0;
          end else if code = isOp then
            if c = '-then begin
              sign := -sign;
              Continue
            end;

          code := isOp;
          if opOrder[c] <= opOrder[Ops[Length(Ops)]] then begin
            while ops[length(ops)] <> '(do begin
              dec(sp);
              case ops[length(ops)] of
                '+': numstack[sp - 1] := numstack[sp - 1] + numstack[sp];
                '-': numstack[sp - 1] := numstack[sp - 1] - numstack[sp];
                '*': numstack[sp - 1] := numstack[sp - 1] * numstack[sp];
                '/': numstack[sp - 1] := numstack[sp - 1] div numstack[sp];
              end;
              numstack[sp] := 0;
              setlength(ops, length(ops) - 1);
            end;
          end;
          if c = ')then
            setlength(ops, length(ops) - 1)
          else
            ops := ops + c;
        end;
    end;
  result := Numstack[0];
end;
Ich find's "schön" kompakt. Na ja, 'schön' ist was anderes...


Hab diesen Code in einen Testrechner eingebaut, der kennt aber
Delphi-Quellcode:
for c in term do
    case c of
      '0'..'9': begin
nicht... Also kennt er schon, ist aber nicht anwendbar...???

[edit=alzaimar] Mfg, alzaimar[/edit]
  Mit Zitat antworten Zitat
gammatester

Registriert seit: 6. Dez 2005
999 Beiträge
 
#36

Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl

  Alt 20. Okt 2009, 16:09
Zitat von Delphi-Narr:

Hab diesen Code in einen Testrechner eingebaut, der kennt aber
Delphi-Quellcode:
for c in term do
    case c of
      '0'..'9': begin
nicht... Also kennt er schon, ist aber nicht anwendbar...???
Meinst Du for c in term do? Das kannst Du ersetzen durch
Delphi-Quellcode:
for i:=1 to length(term) do begin
  c := term[i];
  case c of
  //...
end;
Aber Vorsicht! Der Code rechnet zwar mit Klammern aber trotzdem nicht richtig: '3*5+4*2/2' ergibt 11 statt 19!
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.033 Beiträge
 
Delphi 12 Athens
 
#37

Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl

  Alt 20. Okt 2009, 16:22
Zitat von gammatester:
Aber Vorsicht! Der Code rechnet zwar mit Klammern aber trotzdem nicht richtig: '3*5+4*2/2' ergibt 11 statt 19!
aus diesem Grund hatte ich bei meinem Code alles getrennt und dort
erst die Vorzeichen +x und -x
dann die Punktrechnungen *, /, DIV und MOD
und erst zum Schluß + und -
berechnen lassen

sonst stimmt die Reihenfolge natürlich nicht.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#38

Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl

  Alt 20. Okt 2009, 20:03
Zitat von gammatester:
Aber Vorsicht! Der Code rechnet zwar mit Klammern aber trotzdem nicht richtig: '3*5+4*2/2' ergibt 11 statt 19!
Danke für den Hinweis. Ich nehm den code oben mal raus und prüfe, wieso das so ist.

[edit] Verbesserter Code[/edit]
Delphi-Quellcode:
function Eval(Term: string): Integer;
  function _Eval(term: string; var i: Integer): Integer;
  const
    isNone = 0;
    isNum = 1;
    isOp = 2;

  var
    numStack: array[0..10] of Integer;
    number, code, sign, sp, j: Integer;
    Ops: string;
    c: Char;

    function OpOrder(c: Char): Integer;
    begin
      if c = '$then
        Result := -1
      else
        Result := (Pos(c, '+-*/') + 1) div 2;
    end;

  begin
    fillchar(numstack, sizeof(numstack), 0);
    sign := 1;
    Ops := '$';
    SP := 0;
    number := 0;
    Result := 0;
    code := isNone;
    while i < length(term) do begin
      inc(i);
      c := term[i];
      case c of
        '0'..'9': begin
            number := 10 * number + ord(c) - 48;
            code := isNum;
          end;
        '(': begin
            number := _Eval(term, i);
            code := isNum;
          end;
        ' ': continue;
        '+', '-', '*', '/', ')':
          begin
            if code = isNum then begin
              numStack[SP] := sign * number;
              sign := 1;
              inc(SP);
              code := isNone;
              number := 0;
            end else if code = isOp then begin
              if c = '-then
                sign := -sign;
              Continue
            end;
            code := isop;
            if Length(Ops) > 1 then begin
              while opOrder(c) <= OpOrder(Ops[Length(Ops)]) do begin
                dec(sp);
                case Ops[Length(Ops)] of
                  '*': numstack[sp - 1] := numstack[sp - 1] * numstack[sp];
                  '/': numstack[sp - 1] := numstack[sp - 1] div numstack[sp];
                  '+': numstack[sp - 1] := numstack[sp - 1] + numstack[sp];
                  '-': numstack[sp - 1] := numstack[sp - 1] - numstack[sp];
                end;
                numStack[sp] := 0;
                setLength(Ops, length(Ops) - 1);
              end;
            end;
            Ops := Ops + c;
            if c = ')then begin
              number := NumStack[0];
              break;
            end;

          end;
      end;
    end;
    result := Number;
  end;

var
  i: Integer;

begin
  i := 0;
  Result := _Eval('(' + term + ')', i);
end;
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat
Benutzerbild von Delphi-Narr
Delphi-Narr

Registriert seit: 29. Aug 2009
Ort: Duisburg
437 Beiträge
 
Delphi 2007 Professional
 
#39

Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl

  Alt 23. Okt 2009, 11:06
Ich habe jetzt versucht, in SL alles auszurechnen...

Sl enthält bspw.

1
+
2
*
3

Ich hab jetzt überlegt, ich wiederhole jetzt etwas, bis SL nur noch eine Zeile hat.
Nur weiß ich nicht, wie ich das anstellen soll... Ich habs mit Repeat Until versucht:


Delphi-Quellcode:
begin
               i:=0;
               repeat
                      if SL[i]='*then
                         begin
                               SL[SL.Count-1]:=(FloatToStr(StrToFloat(SL[i-1])*StrToFloat(SL[i+1])));
                               {Zahl vor und nach dem * werden multipliziert und in die Zeile der ersten Zahl geschrieben???}
                               SL.Delete(SL.Count);
                               {Jetzt soll die Zeile des Operators gelöscht werden}
                               SL.Delete(SL.Count+1);{und die der zweiten Zahl}
                               i:=i+1;
                               {Geht zur Position des nächsten Rechenzeichens}
                               exit;
                               {Beendet, da wieder nach * gesucht werden soll->Neubeginn ab Repeat}
                         end;
                      if SL[i]='/then
                         begin
                               SL[SL.Count-1]:=(FloatToStr(StrToFloat(SL[i-1])/StrToFloat(SL[i+1])));
                               SL.Delete(SL.Count);
                               SL.Delete(SL.Count+1);
                               i:=i+1;
                               exit;
                         end;
                      if SL[i]='+then
                         begin
                               SL[SL.Count-1]:=(FloatToStr(StrToFloat(SL[i-1])+StrToFloat(SL[i+1])));
                               SL.Delete(SL.Count);
                               SL.Delete(SL.Count+1);
                               i:=i+1;
                               exit;
                         end;
                      if SL[i]='-then
                         begin
                               SL[SL.Count-1]:=(FloatToStr(StrToFloat(SL[i-1])-StrToFloat(SL[i+1])));
                               SL.Delete(SL.Count);
                               SL.Delete(SL.Count+1);
                               i:=i+1;
                               exit;
                         end;
                     
               until SL.Count = 1;

Ich denke mal, das ist ziemlich falsch...
Also den ersten Teil hab ich jetzt verstanden (StringList erstellen), aber jetzt weiß ich nicht weiter
Bitte helft mir nochmal!!!


Liebe Grüße!
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.033 Beiträge
 
Delphi 12 Athens
 
#40

Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl

  Alt 23. Okt 2009, 12:37
Bei deiner Schleife würde i zuerst beim + vorbeikommen und dieses auflösen.

Jetzt aber einfach auf die Idee zu kommen die Schleife rückwärts laufen zu lassen wäre auch eine blöde Idee,
(bevor zu also danfängst darüber nachzudenken)
denn 1*2+3 würde dann wiederum falsch ausgewertet.



du mußt einzelne/mehere Schleifen nacheinander machen ... und zwar für alle Stufen einzeln


Vorzeichen (+-) - Punktoperationen (*/) - Strichoperationen (+-) ... genauso, wie man es auch auf'm Zettel selber machen würde

- in der ersten Schleife nur die Vorzeichen (+ und -)
also wenn "{keine Zahl, bzw. Operator} {+|-} {Zahl}"

- dann die nächste Stufe die Punkte (* und : aka /)
also wenn "{zahl} {*|/} {zahl}"

- und nun die Striche (+ und -)
also wenn "{zahl} {+|-} {zahl}"

siehe Beitrag #25

der Funktionsinterpreter vom Delphi-Treff kann das alles in nur einer Schleife machen, da er dort eine andere Verschachtelung der Zahlen und Operatoren genutzt wird.
* + 1 2 3
da kann man immer alles gleich ausrechnen, welches "{operator} {zahl} {zahl}" entspricht und muß auf keine Reihenfolge achten, da die Reihenfolge durch die Verschachtelung vorgegeben wird


also deinen Code erstmal in 2 Schleifen zerlegen
Delphi-Quellcode:
begin
               i:=0;
               while i < SL.Count do
                  begin
                      if SL[i]='*then
                         begin
                               SL[SL.Count-1]:=(FloatToStr(StrToFloat(SL[i-1])*StrToFloat(SL[i+1])));
                               {Zahl vor und nach dem * werden multipliziert und in die Zeile der ersten Zahl geschrieben???}
                               SL.Delete(SL.Count);
                               {Jetzt soll die Zeile des Operators gelöscht werden}
                               SL.Delete(SL.Count);{und die der zweiten Zahl}
                               {etwas wurde gefunden - fange von vorn an}
                               i := 0;
                         end
                      else
                      if SL[i]='/then
                         begin
                               SL[SL.Count-1]:=(FloatToStr(StrToFloat(SL[i-1])/StrToFloat(SL[i+1])));
                               SL.Delete(SL.Count);
                               SL.Delete(SL.Count);
                               i := 0;
                         end
                      else
                         i := i + 1;
                  end;
               i:=0;
               while i < SL.Count do
                  begin
                      if SL[i]='+then
                         begin
                               SL[SL.Count-1]:=(FloatToStr(StrToFloat(SL[i-1])+StrToFloat(SL[i+1])));
                               SL.Delete(SL.Count);
                               SL.Delete(SL.Count);
                               i := 0;
                         end
                      else
                      if SL[i]='-then
                         begin
                               SL[SL.Count-1]:=(FloatToStr(StrToFloat(SL[i-1])-StrToFloat(SL[i+1])));
                               SL.Delete(SL.Count);
                               SL.Delete(SL.Count);
                               i := 0;
                         end
                      else
                         i := i + 1;
                  end;
wenn am Ende mehr als ein Eintrag in SL vorliegt, dann stimmte etwas mit dem Term nicht, bzw. du hast etwas noch nicht umgewandelt (z.B. weil der Operator/Befehl noch nicht implementiert ist)
hier z.B. "1 + 2 2 * 3" würde dein Code jetzt "3 6" ausgeben, da die letzen 2 Einträge nicht behandelt werden
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 4 von 5   « Erste     234 5      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:06 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz