Ajout d'un interpréteur arithmétique

This commit is contained in:
Marc Baloup 2014-12-26 00:12:28 +01:00
parent 37f8ea1b00
commit 526e724db5
2 changed files with 772 additions and 0 deletions

View File

@ -0,0 +1,761 @@
package net.mc_pandacraft.java.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 <EFBFBD>
- ecriture formatee d'expression (<EFBFBD> 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 <EFBFBD> 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 -2:
string.append('y');
break;
case -1:
string.append('x');
break;
case 0:
string.append(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("<EFBFBD>(");
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)=='<27>') 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 input = new StringBuffer(expr);
JArithmeticInterpreter jai = JArithmeticInterpreter.constructTree(input,input.length(),0);
if (jai==null)
throw new IllegalArgumentException("Le calcul passé en paramètre est invalide");
return jai.computeTree();
}
/*
public static void main(String args[]) {
String disp_res = StringUtil.formatDouble(JArithmeticInterpreter.getResultFromExpression("1245.25*2"));
System.out.println(disp_res);
} //*/
}

View File

@ -0,0 +1,11 @@
package net.mc_pandacraft.java.util;
public class StringUtil {
public static String formatDouble(double d)
{
if(d == (long) d)
return String.format("%d",(long)d);
else
return String.valueOf((float)d);
}
}