package fr.pandacube.util; //****************************************************************************** //*** //*** INTERPRETEUR ARITHMETIQUE version 2.1 Version Java //*** //*** //*** //****************************************************************************** /* Historique: 2.1: - Version Java disponible: # les operateurs mathematiques disponibles sont ceux de Java donc certains manquent. 2.0: - Portage en C++ et debut en Java Version C++: - Meilleure gestion memoire lors de la construction de l'expression. - Acceleration de certaines operations. Version Java: - Premiere version. Normalement ca doit marcher 1.3b: ajoute les fonctions suivantes: (NON DISTRIBUEE) - reconnaissance du symbole � - ecriture formatee d'expression (� ameliorer) 1.2: corrige les bugs suivants: - erreur sur l'interpretation de fonctions unaires imbriquees telles que ln(exp(x)). - la fonction puissance (pour les puissances entieres). ajoute: - la verification de la chaine entree (voir code d'erreur) - la verification de l'existence de l'evaluation (voir code d'erreur) 1.1: corrige un bug au niveau de l'interpretation des fonctions du type: exp(-(x+y)) 1.0: premiere version Le code source peut etre librement modifie et distribue. Puisqu'il s'agit d'un essai en Java, le code ne doit pas etre super genial et merite sans doute quelques modifications.En particulier, il serait interessant de rajouter le support des Exceptions pour les calculs (division par zero, etc...). */ // Classe servant � palier l'absence de passage par variables ou reference class VariableInt { public int mValue; } // Classe principale public class JArithmeticInterpreter { // Variables int mOperator; double mValue; JArithmeticInterpreter fg, fd; // Methods // .................................................................................... // Node private JArithmeticInterpreter() { this(0, 0, null, null); } // .................................................................................... // Node private JArithmeticInterpreter(int Operator, double Value, JArithmeticInterpreter Fg, JArithmeticInterpreter Fd) { mOperator = Operator; mValue = Value; fg = Fg; fd = Fd; } private JArithmeticInterpreter(int Operator, double Value) { this(Operator, Value, null, null); } // .................................................................................... // Construct_Tree private static JArithmeticInterpreter constructTree(StringBuffer string, int length, int error) { int imbric, Bimbric; int priorite, ope; int position, positionv, i, j; int opetemp = 0; int espa = 0, espat = 0; int caspp = 0; JArithmeticInterpreter node; // Initialisation des variables if (length <= 0) { error = 3; return null; } ope = 0; imbric = 0; Bimbric = 128; priorite = 6; i = 0; positionv = position = 0; // Mise en place des donnees sur le morceau de chaine while (i < length) if (((string.charAt(i) > 47) && (string.charAt(i) < 58)) || (string.charAt(i) == '�')) { if (priorite > 5) { priorite = 5; positionv = i; } i++; } else if ((string.charAt(i) > 96) && (string.charAt(i) < 117)) { VariableInt Vopetemp, Vespat; Vopetemp = new VariableInt(); Vespat = new VariableInt(); Vopetemp.mValue = opetemp; Vespat.mValue = espat; FindOperator(Vopetemp, Vespat, string, i); opetemp = Vopetemp.mValue; espat = Vespat.mValue; if (opetemp >= 0) { if (imbric < Bimbric) { Bimbric = imbric; ope = opetemp; position = i; priorite = 4; espa = espat; } else if ((imbric == Bimbric) && (priorite >= 4)) { ope = opetemp; position = i; priorite = 4; espa = espat; } j = i + 1; i += espat; while (j < i) j++; } else if (string.charAt(i) == 't') { if (priorite == 6) ope = -1; i++; } else if (string.charAt(i) == 'p') { if (priorite == 6) ope = -2; i++; } else if (string.charAt(i) == 'r') { if (priorite == 6) ope = -2; i++; } else if (string.charAt(i) == 'n') { if (priorite == 6) ope = -1; i++; } else { error = 2; // symbole non reconnu return null; } } else switch (string.charAt(i)) { case '(': imbric++; i++; break; case ')': imbric--; i++; break; case '+': if (imbric < Bimbric) { Bimbric = imbric; priorite = 1; ope = 1; position = i; caspp = 0; } else if ((imbric == Bimbric) && (priorite >= 1)) { priorite = 1; ope = 1; position = i; caspp = 0; } i++; break; case '-': if (imbric < Bimbric) { if ((i - 1) < 0) { if (priorite > 5) { priorite = 1; position = i; ope = 2; Bimbric = imbric; caspp = 1; } } else if (string.charAt(i - 1) == '(') { if (priorite > 1) { priorite = 1; position = i; Bimbric = imbric; caspp = 1; ope = 2; } } else { Bimbric = imbric; priorite = 1; ope = 2; position = i; caspp = 0; } } else if ((imbric == Bimbric) && (priorite >= 1)) if ((i - 1) < 0) { if (priorite > 5) { priorite = 1; position = i; ope = 2; caspp = 1; } } else if (string.charAt(i - 1) == '(') { if (priorite > 1) { priorite = 1; position = i; caspp = 1; ope = 2; } } else { priorite = 1; ope = 2; position = i; caspp = 0; } i++; break; case '*': if (imbric < Bimbric) { Bimbric = imbric; priorite = 2; ope = 3; position = i; } else if ((imbric == Bimbric) && (priorite >= 2)) { priorite = 2; ope = 3; position = i; } i++; break; case '/': if (imbric < Bimbric) { Bimbric = imbric; priorite = 2; ope = 4; position = i; } else if ((imbric == Bimbric) && (priorite >= 2)) { priorite = 2; ope = 4; position = i; } i++; break; case '^': if (imbric < Bimbric) { Bimbric = imbric; priorite = 3; ope = 5; position = i; } else if ((imbric == Bimbric) && (priorite >= 3)) { priorite = 3; ope = 5; position = i; } i++; break; case '.': i++; break; default: error = 2; // symbole non reconnu return null; } if (imbric != 0) { error = 1; // erreur de "parenthesage" return null; } // Traitement des donnees if (priorite == 6) { node = new JArithmeticInterpreter(ope, 0.0); return node; } else if (caspp == 1) { node = new JArithmeticInterpreter(2, 0); node.fg = new JArithmeticInterpreter(0, 0); node.fd = new JArithmeticInterpreter(); if ((length - position - 1 - Bimbric) == 0) { // argument absent error = 3; return null; } StringBuffer temp = CopyPartialString(string, (position + 1), (length - 1 - Bimbric)); node.fd = constructTree(temp, (length - position - 1 - Bimbric), error); return node; } else if (priorite == 5) { node = new JArithmeticInterpreter(0, calc_const(string, positionv), null, null); return node; } else if (ope > 5) { node = new JArithmeticInterpreter(ope, 0, null, null); if ((length - position - espa - Bimbric) == 0) { // argument absent error = 3; return null; } StringBuffer temp = CopyPartialString(string, (position + espa), (length - 1)); node.fg = constructTree(temp, (length - position - espa - Bimbric), error); return node; } else { node = new JArithmeticInterpreter(ope, 0, null, null); if ((position - Bimbric) == 0) { // argument absent error = 3; return null; } StringBuffer temp = CopyPartialString(string, Bimbric, (position - 1)); node.fg = constructTree(temp, (position - Bimbric), error); if ((length - position - 1 - Bimbric) == 0) { // argument absent error = 3; return null; } temp = CopyPartialString(string, (position + 1), (length - 1 - Bimbric)); node.fd = constructTree(temp, (length - position - 1 - Bimbric), error); return node; } } // .................................................................................... private double computeTree() { if (mOperator == 0) return mValue; int error = 0; double valueL = fg.computeTree(); if (error != 0) return 0; double valueR = 0; if (fd != null) valueR = fd.computeTree(); if (error != 0) return 0; switch (mOperator) { case 1: // + return (valueL + valueR); case 2: // - return (valueL - valueR); case 3: // * return (valueL * valueR); case 4: // - if (valueR == 0) { error = 1; return 0; } return (valueL / valueR); case 5: // ^ return Math.pow(valueL, valueR); case 6: // exp return Math.exp(valueL); case 7: // ln if (valueL <= 0) { if (valueL < 0) error = 2; else error = 1; return 0; } return (Math.log(valueL) / Math.log(2)); case 8: // log if (valueL <= 0) { if (valueL < 0) error = 2; else error = 1; return 0; } return Math.log(valueL); case 9: // sqrt if (valueL < 0) { error = 2; return 0; } return Math.sqrt(valueL); case 10: // abs return Math.abs(valueL); case 11: return Math.sin(valueL); // sin case 12: return Math.cos(valueL); // cos case 13: return Math.tan(valueL); // tan case 14: return Math.asin(valueL); // asin case 15: return Math.acos(valueL); // acos case 16: return Math.atan(valueL); // atan default: return 0; } } // .................................................................................... // Write_Tree private void writeTree(StringBuffer string) { boolean parenthese = false; switch (mOperator) { case 0: string.append(StringUtil.formatDouble(mValue)); break; case 1: fg.writeTree(string); string.append('+'); fd.writeTree(string); break; case 2: if ((fg.mOperator == 0) && (fg.mValue == 0)) ; else fg.writeTree(string); string.append('-'); if ((fd.mOperator == 1) || (fd.mOperator == 2)) { parenthese = true; string.append('('); } fd.writeTree(string); if (parenthese == true) string.append(')'); break; case 3: if ((fg.mOperator == 1) || (fg.mOperator == 2)) { parenthese = true; string.append('('); } fg.writeTree(string); if (parenthese == true) string.append(')'); parenthese = false; string.append('*'); if ((fd.mOperator == 1) || (fd.mOperator == 2)) { parenthese = true; string.append('('); } fd.writeTree(string); if (parenthese == true) string.append(')'); break; case 4: if ((fg.mOperator == 1) || (fg.mOperator == 2)) { parenthese = true; string.append('('); } fg.writeTree(string); if (parenthese == true) string.append(')'); parenthese = false; string.append('/'); if ((fd.mOperator > 0) && (fd.mOperator < 5)) { parenthese = true; string.append('('); } fd.writeTree(string); if (parenthese == true) string.append(')'); break; case 5: if ((fg.mOperator > 0) && (fg.mOperator < 5)) { parenthese = true; string.append('('); } fg.writeTree(string); if (parenthese == true) string.append(')'); parenthese = false; string.append('^'); if ((fd.mOperator > 0) && (fd.mOperator < 5)) { parenthese = true; string.append('('); } fd.writeTree(string); if (parenthese == true) string.append(')'); break; case 6: string.append("exp("); fg.writeTree(string); string.append(')'); break; case 7: string.append("log("); fg.writeTree(string); string.append(')'); break; case 8: string.append("ln("); fg.writeTree(string); string.append(')'); break; case 9: string.append("sqrt("); fg.writeTree(string); string.append(')'); break; case 10: string.append("|"); fg.writeTree(string); string.append('|'); break; case 11: string.append("sin("); fg.writeTree(string); string.append(')'); break; case 12: string.append("cos("); fg.writeTree(string); string.append(')'); break; case 13: string.append("tan("); fg.writeTree(string); string.append(')'); break; case 14: string.append("asin("); fg.writeTree(string); string.append(')'); break; case 15: string.append("acos("); fg.writeTree(string); string.append(')'); break; case 16: string.append("atan("); fg.writeTree(string); string.append(')'); break; } } // .................................................................................... // calc_const private static double calc_const(StringBuffer chaine, int pos) { int i = pos, j; double temp = 0; int signe = 1; int longueur = chaine.length(); if (chaine.charAt(i) == '-') { signe = -1; i++; } if (chaine.charAt(i) == 'π') return signe * Math.PI; while (i < longueur && chaine.charAt(i) > 47 && chaine.charAt(i) < 58) { temp = temp * 10 + (chaine.charAt(i) - 48); i++; } if (i < longueur && chaine.charAt(i) == '.') { i++; j = 1; while (i < longueur && chaine.charAt(i) > 47 && chaine.charAt(i) < 58) { temp = temp + (chaine.charAt(i) - 48) * Math.exp(-j * 2.30258509); i++; j++; } } return (signe * temp); } // .................................................................................... // FindOperator private static void FindOperator(VariableInt oper, VariableInt esp, StringBuffer chaine, int pos) { switch (chaine.charAt(pos)) { case 'a': switch (chaine.charAt(pos + 1)) { case 'b': esp.mValue = 3; oper.mValue = 10; break; case 'c': esp.mValue = 4; oper.mValue = 15; break; case 's': esp.mValue = 4; oper.mValue = 14; break; case 't': esp.mValue = 4; oper.mValue = 16; break; } break; case 'c': if (chaine.charAt(pos + 1) == 'h') { esp.mValue = 2; oper.mValue = 18; } else if ((chaine.charAt(pos + 1) == 'o') && (chaine.charAt(pos + 2) == 's')) if (chaine.charAt(pos + 3) == 'h') { esp.mValue = 4; oper.mValue = 18; } else { esp.mValue = 3; oper.mValue = 12; } break; case 'e': if ((chaine.charAt(pos + 1) == 'x') && (chaine.charAt(pos + 2) == 'p')) { esp.mValue = 3; oper.mValue = 6; } else oper.mValue = -10; break; case 'l': if (chaine.charAt(pos + 1) == 'n') { esp.mValue = 2; oper.mValue = 7; } else if ((chaine.charAt(pos + 1) == 'o') && (chaine.charAt(pos + 2) == 'g')) { esp.mValue = 3; oper.mValue = 8; } else oper.mValue = -10; break; case 's': if (chaine.charAt(pos + 1) == 'h') { esp.mValue = 2; oper.mValue = 17; } else if (chaine.charAt(pos + 1) == 'q') { esp.mValue = 4; oper.mValue = 9; } else if (chaine.charAt(pos + 3) == 'h') { esp.mValue = 4; oper.mValue = 17; } else { esp.mValue = 3; oper.mValue = 11; } break; case 't': if (chaine.charAt(pos + 1) == 'h') { esp.mValue = 2; oper.mValue = 19; } else if ((chaine.charAt(pos + 1) == 'a') && (chaine.charAt(pos + 2) == 'n')) { if (chaine.charAt(pos + 3) == 'h') { esp.mValue = 4; oper.mValue = 19; } else { esp.mValue = 3; oper.mValue = 13; } } else oper.mValue = -10; break; default: oper.mValue = -10; break; } } // .................................................................................... // CopyPartialString private static StringBuffer CopyPartialString(StringBuffer chaine, int debut, int fin) { StringBuffer chartemp; int a = fin - debut + 1; chartemp = new StringBuffer(a + 1); for (int i = 0; i < a; i++) chartemp.append(chaine.charAt(debut + i)); return chartemp; } public static double getResultFromExpression(String expr, StringBuffer writeTree) { StringBuffer input = new StringBuffer(expr); JArithmeticInterpreter jai = null; try { jai = JArithmeticInterpreter.constructTree(input, input.length(), 0); } catch (Exception e) {} if (jai == null) throw new IllegalArgumentException("Le calcul passé en paramètre est invalide"); if (writeTree != null) { writeTree.setLength(0); jai.writeTree(writeTree); } return jai.computeTree(); } public static double getResultFromExpression(String expr) { return getResultFromExpression(expr, null); } public static void main(String args[]) { StringBuffer b = new StringBuffer(0); String disp_res = StringUtil.formatDouble(JArithmeticInterpreter.getResultFromExpression("1245.25*2", b)); System.out.println(disp_res); System.out.println(b); } // */ }