(5 oktober 2018 Symbolisk kalkylator 1 ) Obligatorisk uppgift 5 En kalkylator som hanterar uttryck symboliskt dvs värden är uttryck inte bara tal. Uppgiften exemplifierar: objektorientering återanvändning av kod klasshierarkier och arv abstrakta klasser datastrukturer rekursion undantagshantering Uppgiften är också en övning i att sätta sig in i och komplettera ett existerande program.
(5 oktober 2018 Symbolisk kalkylator 2 ) Symbolisk kalkylator: Exempel Input : 2*(0.2 + 0.3) = x Result: 1.0 Input : exp(2.0*x)+x Result: 8.38905609893065 Input : "(exp(2*x) + x) Result: exp(2.0*x) + x Input : "(exp(2*x) + x) = y Result: exp(2.0*x) + x Input : y Result: exp(2.0*x) + x Input : &y Result: 8.38905609893065
(5 oktober 2018 Symbolisk kalkylator 3 ) Symbolisk kalkylator: Exempel Input : exp(x-1) + exp("x - 1) = z Result: 1.0 + exp(x - 1) Input : &z Result: 2.0 Input : "sin(2*x) x Result: 2*cos(2*x) Input : sin(2*x) x Result: 0.0 Varför?
(5 oktober 2018 Symbolisk kalkylator 4 ) Symbolisk kalkylator: Exempel Input : exp("x x) / exp(1) + "(x*x) x Result: 1.0 + 2*x Input : &(exp("x x) / exp(1) + "(x*x) x) Result: 3.0 Input : ("x*"y) x y Result: 1.0
(5 oktober 2018 Symbolisk kalkylator 5 ) Oförändrade syntaxdiagram: statement EOL quit vars EOL assignment expression file assignment word = word
(5 oktober 2018 Symbolisk kalkylator 6 ) Oförändrade syntaxdiagram: expression term term factor + eller * eller /
(5 oktober 2018 Symbolisk kalkylator 7 ) Syntaxdiagram för factor Används för att beskriva syntaxen för derivering: y x sin(3*"t) t factor primary (z*exp(z)) z "sin(x*x) x x sin(exp(x*x) x = y) x (Observera den strukturella likheten med assignment!) word
(5 oktober 2018 Symbolisk kalkylator 8 ) Två nya operatorer i primary ( assignment ) function name unary operator primary number variable Error function name: sin, cos, exp, log, abs unary operator: - (unärt minus), " (quote), & (eval)
(5 oktober 2018 Symbolisk kalkylator 9 ) Kommentar till funktionen abs Funktionen abs får betraktas som icke deriverbar. Extrauppgift: Modifiera syntaxen så att absolutbelopp också kan uttryckas på vanligt sätt med vertikalstreck.! Följ upp detta i hela programmet!
(5 oktober 2018 Symbolisk kalkylator 10 ) Intern representation av uttryck Programmet skall läsa uttrycken och bygga upp en internrepresentation i form av ett binärt träd. Exempel: sin(x) + 5*a - 3*(u+1) = z = t och representeras av trädet: = = t z + * sin * 3 + x 5 a u 1
(5 oktober 2018 Symbolisk kalkylator 11 ) Intern representation av uttryck Exempel med eval-, kvot- och deriveringsoperatorerna: "(sin(&x) x = y) = t " = t = y sin x & x
(5 oktober 2018 Symbolisk kalkylator 12 ) Vad vill vi kunna göra med en trädnod? Returnera (sub-)trädet som en String (tostring) " = t Beräkna värdet av det (sub-)träd som har noden som rot (eval) Derivera det (sub-)träd som har noden som rot (diff) sin x = y Ytterligare ett antal metoder som vi kommer att upptäcka. & x Dessa operationer skall finnas för alla noder men de skall utföras på olika sätt typiskt läge för en klasshierarki.
(5 oktober 2018 Symbolisk kalkylator 13 ) Basklassen Sexpr Sexpr eval() Sexpr diff(sexpr).... Sexpr eval görs abstrakt. Varför? Skall diff göras abstrakt? Nja Varför behöver vi inte ha tostring i Sexpr?
(5 oktober 2018 Symbolisk kalkylator 14 ) Vilka typer av noder finns det? Löv: Konstanter och variabler (atomer) Sexpr abstract Noder med ett barn: funktioner, unärt minus, evaluerings- och kvotoperatorerna (unärer) Noder med två barn: =,, +,... (binärer) Atom abstract Unary abstract Sexpr operand Binary abstract Sexpr left Sexpr right
Klasshierarki Sexpr abstract String getname() abstract Sexpr eval(map) abstract int priority() Sexpr diff(sexpr) double getvalue() boolean isconstant() boolean isconstant(double) Atom abstract String tostring() Unary abstract Sexpr operand Binary abstract Sexpr left Sexpr right String tostring() Variable String ident Sexpr eval(map) String getname() Sexpr diff(sexpr) Operator abstract String tostring() Function abstract String tostring() Addition Subtraction Multiplication Division Constant double value Sexpr eval(map) String getname() Sexpr diff(sexpr) boolean isconstant() boolean isconstant(double) Evaluation Quotation Negation Sexpr eval(map) String getname() Sexpr diff(sexpr) Sin Assignment Cos Differentiation Exp Sexpr eval(map) String getname() Log int priority() Sexpr eval(map) Abs String getname() Sexpr eval(map) Sexpr (5diff(Sexpr) oktober 2018 Symbolisk kalkylator 15 )
Atom (5 oktober 2018 Symbolisk kalkylator 16 )
Unary (5 oktober 2018 Symbolisk kalkylator 17 )
Unary (Klassen Abs saknas i figuren) (5 oktober 2018 Symbolisk kalkylator 18 )
(5 oktober 2018 Symbolisk kalkylator 19 ) Binary (Differentiation och Assignment ska inte ha diff-metoder)
(5 oktober 2018 Symbolisk kalkylator 20 ) Återbesök i basklassen Sexpr abstract Sexpr eval(map<string, Sexpr> map); abstract String getname(); public int priority() {return 100; // Useful default double getvalue() {assert false; // Should never occur boolean isconstant() {return false; // Useful default boolean isconstant(double v) {return false; // Useful default Sexpr diff(sexpr x) {throw new EvaluationException(...) Det är inte absolut förbjudet att lägga till fler metoder men det behövs inte!
(5 oktober 2018 Symbolisk kalkylator 21 ) Parsern används för att bygga trädet Exempel: public Sexpr expression() { Sexpr sum = term(); int c; while ((c=tokenizer.getchar())== + c == - ) { tokenizer.nexttoken(); if (c== + ) { sum = new Addition(sum, term()); else { sum = new Subtraction(sum, term()); return sum; (Notera tekniken med en tilldelning i while-villkoret!)
(5 oktober 2018 Symbolisk kalkylator 22 ) Ett till exempel: assignment public Sexpr assignment() { Sexpr value = expression(); while (tokenizer.getchar() == = ) { tokenizer.nexttoken(); if (tokenizer.isword()) { value = new Assignment(value, new Variable(tokenizer.getWord())); tokenizer.nexttoken(); else { throw new SyntaxException("Expected variable after = "); return value;
(5 oktober 2018 Symbolisk kalkylator 23 ) Parsern Parserns uppgift är således 1. att kontrollera syntaxen och 2. att bygga uttrycksträdet. Parsern känner inte till mappen med variabelvärden. Alla beräkningar (i vid bemärkelse) görs av eval-metoderna och det är dessa metoder som upptäcker evalueringsfel.
(5 oktober 2018 Symbolisk kalkylator 24 ) Klassen Addition public class Addition extends Binary { public Addition(Sexpr left, Sexpr right) { super(left, right); public String getname() { return "+"; public int priority() { return 20;
(5 oktober 2018 Symbolisk kalkylator 25 ) Klassen Addition forts public Sexpr eval(map<string,sexpr> map) { return Symbolic.add(left.eval(map), right.eval(map)); public Sexpr diff(sexpr x) { return Symbolic.add(left.diff(x), right.diff(x));
(5 oktober 2018 Symbolisk kalkylator 26 ) Klassen Symbolic Klassen innehåller static-metoder för att sköta symbolisk- och numerisk aritmetik. Exempel: En metod för att utföra additioner public static Sexpr add(sexpr left, Sexpr right) { if (left.isconstant() && right.isconstant()) { return new Constant(left.getValue()+ right.getvalue()); else { return new Addition(left, right); Måste förbättras för att t ex klara uttryck av typen 0 + x Fråga: Varför tror vi att att uttryck av typen 0 + x förekommer?
(5 oktober 2018 Symbolisk kalkylator 27 ) Klassen Symbolic Förbättrad add-metod: public static Sexpr add(sexpr left, Sexpr right) { if (left.isconstant() && right.isconstant()) { return new Constant(left.getValue()+ right.getvalue()); else if (left.isconstant(0)) { return right; else if (right.isconstant(0)) { return left; else { return new Addition(left, right); Kan snyggas till ytterligare
(5 oktober 2018 Symbolisk kalkylator 28 ) Klassen Symbolic Alla operatorer som kan utföra numeriska aritmetik dvs +, -, *, /, sin, cos, exp, log,... ska ha en motsvarande metod i klassen Symbolic! De icke-numeriska operationerna dvs =, &, " och behöver inte ha motsvarande metoder i Symbolic Metoderna i Symbolic ska inte använda eval-metoder och har inte tillgång till variabelvärden. Man behöver inte klura ut alla förenklingar från början - gör enkla implementationer först!
(5 oktober 2018 Symbolisk kalkylator 29 ) Hur skriver man ut uttryck? Använd tostring-metoderna! public abstract class Binary extends Sexpr { protected Sexpr left; protected Sexpr right; public String tostring() { return "(" + left + ")" + getname() + "(" + right + ")";... Fungerar men...
(5 oktober 2018 Symbolisk kalkylator 30 ) Hur kommer man igång? 1. Läs igenom uppgiftsbeskrivningen flera gånger! Fråga om det är något du inte förstår! 2. Kompilera och testkör den givna miniversionen och se vad som fungerar och vad som inte fungerar (bra). 3. Läs koden och se till att du förstår hur den är uppbyggd. 4. Lägg till operationen subtraktion. Du måste både ändra i parsern (se hur du gjorde i den numeriska kalkylatorn), skriva klassen Subtraction samt lägga till en metod i klassen Symbolic.
(5 oktober 2018 Symbolisk kalkylator 31 ) Hur kommer man igång? 4. Skriv klassen Differentiation samt metoderna diff(sexpr) i klasserna Addition och Subtraction. Observera att deriveringsreglerna (diff-metoderna) skall använda sig av metoderna i klassen Symbolic. 5. Fyll på med övriga klasser för som saknas (Division, Quotation, Evaluation, Sin,... ) 6. Se till att tostring-metoderna inte sätter ut onödiga parenteser. 7. Förbättra förenklingarna i Symbolic 8....
(5 oktober 2018 Symbolisk kalkylator 32 ) Några ställen som vi vet att kan vara svåra att förstå Hur ska quote-operatorn evalueras? Hur ska eval-operatorn evalueras? Hur ska deriveringsoperatorn evalueras? Hur ska quote-, eval-, och derveringsoperatorerna deriveras? Hur ska parenteser sättas ut i binära för binära operatorer?
(5 oktober 2018 Symbolisk kalkylator 33 ) En fundering kring metoden isconstant(double x) I klassen Constant: public boolean isconstant(double x) { return value == x; Bra eller dåligt? Alternativ?