PandaLib/src/main/java/fr/pandacube/util/JArithmeticInterpreter.java
2019-10-26 23:15:49 +02:00

763 lines
17 KiB
Java
Raw Blame History

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 <20>
- ecriture formatee d'expression (<28> 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 <20> 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) == '<27>')) {
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);
} // */
}