Priorität ist das ganze Problem
Um 2 + 3 * 4 zu lesen, muss man wissen, dass Multiplikation fester
bindet als Addition, also ist das Ergebnis 14 und nicht 20. Jeder
Operator trägt ein Prioritätslevel und eine Assoziativität.
Multiplikation, Division und der Restoperator stehen über Addition und
Subtraktion; die Potenzierung steht über allen und ist rechtsassoziativ,
also bedeutet 2^3^2 2^(3^2) und ergibt 512, nicht 64.
Das unäre Minus ist der subtile Fall. Die mathematische Konvention
setzt es unter die Potenzierung, weshalb -3^2 gleich -9 ist: der
Exponent gilt für 3 und die Negation gilt für das Ergebnis.
Tabellenkalkulationssoftware widerspricht das bekanntlich und gibt 9
zurück, also wenn Sie je zwei Werkzeuge unterschiedliche Antworten auf
dieselbe Formel gesehen haben, ist das meist der Grund. Dieser
Auswerter folgt der mathematischen Konvention.
Klammern überschreiben alles, und es lohnt sich, sie frei zu verwenden.
Ein Ausdruck, der eine Prioritätstabelle zum Lesen braucht, ist ein
Ausdruck, der früher oder später missverstanden wird.
Shunting-yard, kurz
Der Ausdruck wird zuerst in Token zerlegt - Zahlen, Namen, Operatoren
und Satzzeichen - und dann von Dijkstras Shunting-yard-Algorithmus in
Postfix-Form umgeordnet, wo Operatoren ihren Operanden folgen.
2 + 3 * 4 wird zu 2 3 4 * +. Postfix braucht keine Klammern und
keine Prioritätsregeln, weil die Reihenfolge der Token die Struktur
bereits kodiert, sodass eine einfache Stack-Maschine ihn in einem
einzigen Durchlauf auswerten kann.
Der Algorithmus hält zwei Strukturen: eine Ausgabeliste und einen
Operator-Stack. Zahlen gehen direkt in die Ausgabe; ein Operator
poppt zuerst jeden gestapelten Operator, der mindestens so fest bindet,
bevor er selbst gepusht wird. Klammern wirken als Marker auf dem Stack,
und eine schließende Klammer poppt alles bis zu ihrem Partner zurück.
Funktionsaufrufe reiten als Operatoren mit, deren Argumentzähler bei
jedem gesehenen Komma steigt.
Das ist dieselbe Technik, die in Tabellenkalkulations-Engines und
Abfrageplanern verwendet wird. Sie läuft in linearer Zeit, braucht keine
Rekursion und meldet einen fehlerhaften Ausdruck natürlich: wenn sich
der Stack am Ende nicht sauber leert, war die Eingabe unausgeglichen.
Gleitkomma, ehrlich
Ergebnisse werden in IEEE-754-Doppelgenauigkeit berechnet, derselben
Arithmetik, die jeder Browser und die meisten Programmiersprachen
verwenden. Sie speichert Zahlen binär, und ein Dezimalbruch wie 0,1
hat keine exakte binäre Darstellung, weshalb 0,1 + 0,2 berühmt
0,30000000000000004 statt 0,3 ergibt.
Das Runden der Anzeige auf eine festgelegte Anzahl signifikanter Stellen
versteckt dieses Rauschen, ohne den zugrundeliegenden Wert zu ändern,
was hier die Präzisionssteuerung macht. Auf 12 gesetzt hält die Antwort
lesbar, während noch reichlich Raum vor den 15 bis 17 Stellen bleibt,
die ein Double tatsächlich unterscheiden kann.
Zwei Grenzen sind es wert, erinnert zu werden. Ganze Zahlen bleiben nur
bis 2^53 exakt, also driften sehr große Fakultäten und Produkte ab;
alles über 170! läuft zu Unendlich über. Und das Subtrahieren zweier
fast gleicher Zahlen zerstört die Präzision - die führenden Stellen
kürzen sich weg und nur die verrauschten Nachkommastellen überleben -
eine Formel, die so umgestellt ist, dass sie diese Subtraktion vermeidet,
ist oft weit genauer als die naheliegende Form.