/* Trida Vyraz. ============ Tato trida je soucasti projektu Derivovani. Kazda instance tridy Vyraz v sobe muze obsahovat jednu z nasledujicich informaci (ktera to je, urcuje vlastnost "typ"): tCislo ... ve vlastnosti "hodnota" je ulozena ciselna konstanta tX ... trida Vyraz predstavuje promennou "X" tSoucet, tRozdil, tSoucin, tPodil, tMocnina ... jedna se o soucet, rozdil, soucin, podil nebo mocinu. Operace je definovana mezi dvema vyrazy, coz jsou opet instance tridy "Vyraz" a reference na ne je ulozena ve vlastnostech "levyOperand" a "pravyOperand". Trida ma dva konstruktory - jeden slouzi pro vytvoreni souctu, rozdilu, soucinu, podilu, mocniny a promenne X. Druhy konstruktor pro vytvoreni konstanty. Funkce "zjednodus()" vraci zednoduseny vyraz (provede operace mezi konstantami, nasobeni nulou, atd.) Metoda "zobraz()" vypise vyraz na obrazovku. Metoda "zderivuj()" vraci zderivovany vyraz. Pokud dojde k nejake chybe, ulozi se jeji popis do promenne "chyba". Po osetreni chyby je nutne do teto promenne ulozit hodnotu null. */ package derivovani; import sugar.Sys; public class Vyraz { public static String chyba=null; // popis chyby (pokud k nejake dojde) // typy vyrazu (hodnoty vlastnosti "typ" tridy "Vyraz"): public static char tCislo = 'k'; // cislo public static char tSoucet = '+'; // soucet ( + ) public static char tRozdil = '-'; // rozdil ( - ) public static char tSoucin = '*'; // soucin ( * ) public static char tPodil = '/'; // podil ( / ) public static char tMocnina = '^'; // mocnina ( ^ ) public static char tX = 'x'; // promenna "x" // urovne pro funkci "zpracujVstup": public static int uSoucet = 0; // funkce konci, kdyz narazi na pravou zavorku nebo na konec vstupniho retezce public static int uSoucin = 1; // funkce konci, kdyz narazi na znamenko "+", "-", ")" nebo na konec vstupniho retezce public static int uMocnina = 2; // funkce konci, kdyz narazi na "*", "/", "+, "-", ... // instancni promenne tridy "Vyraz" public char typ; // typ vyrazu public Vyraz levyOperand; // levy operand (vyraz) public Vyraz pravyOperand; // pravy operand (vyraz) public double hodnota; // hodnota vyrazu typu "tvCislo" // konstruktor pro vsechny vyrazy krome vyrazu typu cislo public Vyraz(char typ, Vyraz levyOperand, Vyraz pravyOperand) { this.typ = typ; this.levyOperand = levyOperand; this.pravyOperand = pravyOperand; this.hodnota = 0; } // konstruktor pro vyraz typu cislo public Vyraz(double hodnota) { this.typ = tCislo; this.levyOperand = null; this.pravyOperand = null; this.hodnota = hodnota; } // funkce, ktera zjisti, zda vyraz je cislo a ma hodnotu "testHodnota" private boolean maHodnotu(double testHodnota) { return ((typ==tCislo) && (hodnota==testHodnota)); } // konverze operatoru na uroven operatoru (soucet, soucin, mocnina) public static int urovenOperatoru(char znak) { if ( (znak=='+') || (znak=='-') ) return uSoucet; else if (znak=='^') return uMocnina; else // nasobeni muze byt vyjadreno i bez znaku operatoru return uSoucin; } // procedura, ktera zjednodusi dany vyraz. // Navratovou hodnotou je reference na zjednoduseny vyraz public Vyraz zjednodus() { if (chyba != null) return null; // pokud doslo k chybe, koncim if ((typ==tSoucet) || (typ==tSoucin) || (typ==tRozdil) || (typ==tPodil) || (typ==tMocnina)) { // zjednodusim oba operandy levyOperand = levyOperand.zjednodus(); if (chyba != null) return null; // pokud doslo k chybe, koncim pravyOperand = pravyOperand.zjednodus(); if (chyba != null) return null; // pokud doslo k chybe, koncim // jestlize oba operandy jsou cisla ... if ((levyOperand.typ == tCislo) && (pravyOperand.typ == tCislo)) { if ((typ==tPodil)&&(pravyOperand.hodnota==0)) { chyba = "Nulou nelze delit!"; return null; } if ((typ==tMocnina)&&(levyOperand.hodnota==0)&&(pravyOperand.hodnota==0)) { chyba = "Vyraz [0^0] neni definovany!"; return null; } if (typ == tSoucet ) return new Vyraz(levyOperand.hodnota + pravyOperand.hodnota); if (typ == tRozdil ) return new Vyraz(levyOperand.hodnota - pravyOperand.hodnota); if (typ == tSoucin ) return new Vyraz(levyOperand.hodnota * pravyOperand.hodnota); if (typ == tPodil ) return new Vyraz(levyOperand.hodnota / pravyOperand.hodnota); if (typ == tMocnina) return new Vyraz(Math.pow(levyOperand.hodnota, pravyOperand.hodnota)); } // 0*F = 0, F*0 = 0 if ((typ==tSoucin) && ( levyOperand.maHodnotu(0) || pravyOperand.maHodnotu(0) )) return new Vyraz(0); // 0 + F = F if ((typ == tSoucet) && levyOperand.maHodnotu(0)) return pravyOperand; // F + 0 = F, F - 0 = F if (((typ == tSoucet) || (typ == tRozdil)) && pravyOperand.maHodnotu(0)) return levyOperand; // F * 1 = F if ( (typ == tSoucin) && pravyOperand.maHodnotu(1) ) return levyOperand; // 1 * F = F if ( (typ == tSoucin) && levyOperand.maHodnotu(1) ) return pravyOperand; // 1 ^ F = 1 if ( (typ == tMocnina) && levyOperand.maHodnotu(1) ) return new Vyraz(1); // F ^ 1 = F if ( (typ == tMocnina) && pravyOperand.maHodnotu(1) ) return levyOperand; // 0 ^ F = 0 if ((typ==tMocnina) && levyOperand.maHodnotu(0)) return new Vyraz(0); // F ^ 0 = 1 if ((typ==tMocnina) && pravyOperand.maHodnotu(0)) return new Vyraz(1); // (F ^ r) ^ s = F ^ (r*s) if ((typ==tMocnina) && (pravyOperand.typ==tCislo) && (levyOperand.typ==tMocnina) && (levyOperand.pravyOperand.typ==tCislo)) { Vyraz soucin = new Vyraz(levyOperand.pravyOperand.hodnota * pravyOperand.hodnota); return new Vyraz(tMocnina, levyOperand.levyOperand, soucin); } // (a * F) * b = (a * b) * F if ((typ==tSoucin) && (pravyOperand.typ==tCislo) && (levyOperand.typ==tSoucin) && (levyOperand.levyOperand.typ==tCislo)) { Vyraz soucin = new Vyraz(levyOperand.levyOperand.hodnota * pravyOperand.hodnota); return new Vyraz(tSoucin, soucin, levyOperand.pravyOperand); } // (F * a) * b = (a * b) * F if ((typ==tSoucin) && (pravyOperand.typ==tCislo) && (levyOperand.typ==tSoucin) && (levyOperand.pravyOperand.typ==tCislo)) { Vyraz soucin = new Vyraz(levyOperand.pravyOperand.hodnota * pravyOperand.hodnota); return new Vyraz(tSoucin, soucin, levyOperand.levyOperand); } // a * (b * F) = (a * b) * F if ((typ==tSoucin) && (levyOperand.typ==tCislo) && (pravyOperand.typ==tSoucin) && (pravyOperand.levyOperand.typ==tCislo)) { Vyraz soucin = new Vyraz(levyOperand.hodnota * pravyOperand.levyOperand.hodnota); return new Vyraz(tSoucin, soucin, pravyOperand.pravyOperand); } } // vyraz neumim zjednodusit return this; // beze zmeny } // metoda, ktera zobrazi tento vyraz private void zobraz() { if (typ==tX) Sys.p("x"); if (typ==tCislo) { if (hodnota < 0) Sys.p("("); Sys.p(hodnota); if (hodnota < 0) Sys.p(")"); } if ((typ==tSoucet)||(typ==tRozdil)||(typ==tSoucin)||(typ==tPodil)||(typ==tMocnina)) { boolean zavorkyVlevo = ((levyOperand.typ==tSoucet)||(levyOperand.typ==tRozdil)||(levyOperand.typ==tSoucin)||(levyOperand.typ==tPodil)) && (urovenOperatoru(levyOperand.typ) < urovenOperatoru(typ)); boolean zavorkyVpravo = ((pravyOperand.typ==tSoucet)||(pravyOperand.typ==tRozdil)||(pravyOperand.typ==tSoucin)||(pravyOperand.typ==tPodil)||(pravyOperand.typ==tMocnina)) && (urovenOperatoru(pravyOperand.typ) <= urovenOperatoru(typ)); if ((typ==tSoucet) && (pravyOperand.typ==tSoucet)) zavorkyVpravo = false; if ((typ==tSoucet) && (pravyOperand.typ==tRozdil)) zavorkyVpravo = false; if ((typ==tSoucin) && (pravyOperand.typ==tSoucin)) zavorkyVpravo = false; if ((typ==tSoucin) && (pravyOperand.typ==tPodil )) zavorkyVpravo = false; if (zavorkyVlevo) Sys.p("("); levyOperand.zobraz(); if (zavorkyVlevo) Sys.p(")"); Sys.p(typ); if (zavorkyVpravo) Sys.p("("); pravyOperand.zobraz(); if (zavorkyVpravo) Sys.p(")"); } } // metoda, ktera zobrazi tento vyraz spolu se zpravou public void zobraz(String zprava) { Sys.p(zprava); zobraz(); Sys.pln(); } // funkce, ktera zjisti, zda vyraz obsahuje promennou x private boolean obsahujeX() { if ((typ==tSoucet) || (typ==tSoucin) || (typ==tRozdil) || (typ==tPodil) || (typ==tMocnina)) { if (levyOperand.obsahujeX()) return true; if (pravyOperand.obsahujeX()) return true; } if (typ==tX) return true; return false; } // funkce, ktera vyraz zderivuje public Vyraz zderivuj() { if (chyba != null) return null; // pokud doslo k chybe, koncim // derivace souctu (rozdilu) je soucet (rozdil) derivaci if ((typ==tSoucet) || typ==tRozdil) { Vyraz derF = levyOperand.zderivuj(); Vyraz derG = pravyOperand.zderivuj(); if (chyba != null) return null; // pokud doslo k chybe, koncim return new Vyraz(typ, derF, derG); } // derivace soucinu (F*G)' = F'*G + F*G' if (typ==tSoucin) { Vyraz F = levyOperand; Vyraz G = pravyOperand; Vyraz derF = F.zderivuj(); Vyraz derG = G.zderivuj(); if (chyba != null) return null; // pokud doslo k chybe, koncim Vyraz soucinA = new Vyraz(tSoucin, derF, G); Vyraz soucinB = new Vyraz(tSoucin, F, derG); return new Vyraz(tSoucet, soucinA, soucinB); } // derivace podilu (F/G)' = (F'*G - F*G') / G^2 if (typ==tPodil) { Vyraz F = levyOperand; Vyraz G = pravyOperand; Vyraz derF = F.zderivuj(); Vyraz derG = G.zderivuj(); if (chyba != null) return null; // pokud doslo k chybe, koncim Vyraz soucinA = new Vyraz(tSoucin, derF, G ); Vyraz soucinB = new Vyraz(tSoucin, F, derG ); Vyraz dvojka = new Vyraz(2 ); Vyraz rozdil = new Vyraz(tRozdil, soucinA, soucinB); Vyraz mocnina = new Vyraz(tMocnina, G, dvojka ); return new Vyraz(tPodil, rozdil, mocnina); } // derivace mocniny F^n = n * F^(n-1) * F' if (typ==tMocnina) { Vyraz F = levyOperand; Vyraz n = pravyOperand; if (n.obsahujeX()) { chyba = "Exponent nesmi obsahovat promennou [x]!"; return null; } else { Vyraz derF = F.zderivuj(); if (chyba != null) return null; // pokud doslo k chybe, koncim Vyraz jednicka = new Vyraz(1); Vyraz rozdil = new Vyraz(tRozdil, n, jednicka ); Vyraz mocnina = new Vyraz(tMocnina, F, rozdil ); Vyraz soucin = new Vyraz(tSoucin, n, mocnina ); return new Vyraz(tSoucin, soucin, derF); } } // derivace konstanty je nula if (typ==tCislo) return new Vyraz(0); // derivace "x" je "1" if (typ==tX) return new Vyraz(1); // chyba chyba = "Pri derivovani doslo k vnitrni chybe programu. Vyraz neznameho typu!"; return null; } }