Calculatrice de chaines mathématiques

Soyez le premier à donner votre avis sur cette source.

Vue 12 289 fois - Téléchargée 809 fois

Description

Ce petit programme montre comment utiliser l'unité expression contenu dans le zip.
Il peut donc calculer des chaines mathématiques tels que : (10+2*3)-5*sin(60)
Il respecte les priorités des opérateurs, fait les calculs dans les parenthèses avant les autres.
Il est sans prétension mais permet de comprendre comment ajouter dans un programme la faculté de calculer des expressions mathématiques. Je me suis basé d'une source parue dans Pascalissime. Ça fait très longtemps que j'ai fait ce source mais je pense qu'il peut intéresser quelques personnes.

Conclusion :


Je suis ouvert à toutes vos suggestions pertinentes.

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

kevinou55
Messages postés
15
Date d'inscription
mardi 5 juin 2007
Statut
Membre
Dernière intervention
12 février 2008

J'ai trouvé une solution pour le 2(5+8) !!! lol
au tout debut de ta fonction eval, lorsque tu compte le nombre de parentheses ouvrantes et fermantes:
deja il au faire un Repeat-- Until ensuite
il faut tester d'abord les parentheses fermantes puis dans le test des ouvrantes tu regarde si le caractère précédent est un nombre.
Si c'est le cas tu ajoute un '*' avant et tu incremente i une fois de plus

En gros tu fais comme ca lol (encore desolé pour les variables)



i:=1;
Repeat
if (strTemp[i]=')')
then begin
parant_droite:=parant_droite+1;
strTemp[i]:=')';
end;
if (strTemp[i]='(')
then begin
strTemp[i]:='(';
parant_gauche:=parant_gauche+1;
if strTemp[i-1] in ['0'..'9'] //si le caractère precedent est un nombre
then begin
//on prend la partie avant la prenthese on ajoute '*' puis le reste
strTemp:=copy(strTemp,0,i-1)+'*'+copy(strTemp,i,length(strTemp)-i+1);
//il faut incrementer i car sinon la parenthes est comptée 2 fois
inc(i);
end;
end;
strTemp[i]:=upcase(strTemp[i]); //on met en majuscules
inc(i);
until i>Length(strTemp);


En esperant que vous ne trouverez pa de bugs ;)
Oniria
Messages postés
296
Date d'inscription
dimanche 14 mars 2004
Statut
Membre
Dernière intervention
18 décembre 2014
2
Bonjour,

Merci barbichette, c'est vrai, la procédure n'accepte pas deux opérateurs en même temps.
Attention, l'évaluation ne comprend pas non plus 2(5+8) par exemple car il lui faut systématiquement les opérateurs. Il faut mettre dans ce cas 2*(5+8).

Je vais vérifier si tu as raison, et je ferais une correction pour en faire profiter le plus grand nombre.

En tout cas merci beaucoup. A force de voir le même code, on fini par ne plus voir ces défauts.

Oniria
cs_barbichette
Messages postés
243
Date d'inscription
lundi 30 octobre 2000
Statut
Membre
Dernière intervention
15 juillet 2013

je viens de voir un petit bug.
Losque la chaine commence par un signe - suivi d'une fonction
ex : "-cos(10)" ou encore "2*(-exp(10))"
Ou encore "3-cos" <= oubli d'une valeur après
il y a bug car le programme essai de faire ça :
pilval[-1]:=pilval[-1]-pilval[0]; <== indice en dehors des limites.
donc
il faut toujours vérifier que pilval contient toujours assez de valeur pour faire les opérations.

Je sais que ce bout de code ne vient pas de toi, mais voilà une version un peu modifiée avec des tests en moins et l'utilisation de l'opérateur "in"

sinon, c'est formidable comme performance en si peu de lignes.

barbichette

//******************************************************************************
// Cette fonction a été récupérée dans la revue Pascalissime
// elle permet d'effectuer les calculs simples sans parenthéses.
// ex : 10*25+4E-3-s10
// ici s est la simplification de sin (fonction sinus)
//******************************************************************************
Function Evalu_exp( gisp : string ) : real;
VAR giap : string;
g_postfix : array[0..255] of string;
lip,lpp : integer; // index dans infix, index dans g_postfixe
l_indice,indval,l_base : integer;
pilval : array[0..255] of real;
symb : char;
BEGIN
// convertis_infix_en_postfix
// La notation infix est celle utilisée couramment en math
// par exemple A+(B-C)
// la notation postfix nous donne pour cet exemple ABC-+
// Cette notation fait intervenir la notion de pile.
// donc ABC-+ sera calculé de la facon suivante:
// le premier caractére est A : mise sur la pile
// le deuxiéme est B : mise sur la pile
// le troisieme est C : mise sur la pile
// le quatrieme est - : dépile C et B, on effectue B-C puis le résultat est remis dans la pile.
// appelons B-C la valeur D=B-C (juste pour la comprehension)
// la pile resemble à : A D +
// la cinquiéme étape est + : on dépile D et A, on calcule A+D puis le résultat est remis dans la pile
// a ce moment, la pile ne contient plus qu'un élément c'est le résultat R
//
// La conversion se fait avec les prioritées de chaque opérateur.


// convertion de la chaine en un tableau de valeur ou de propriete

giap:='';
l_base:=0;
gisp:=gisp+'z';

FOR l_indice:=1 TO length(gisp) do
Begin
// si on a un chiffre (éventuellement avec un - ou un + devant),
if (gisp[l_indice] in ['0'..'9','E','.',','])
or ((l_indice=1) and (gisp[1]='-'))
or ((l_indice>1) and (gisp[l_indice]='-') and not (gisp[l_indice-1] in ['0'..'9']))
or ((l_indice>1) and (gisp[l_indice]='+') and (gisp[l_indice-1]='E')) then
begin
giap:=giap+gisp[l_indice];
end
else
// sinon, c'est un opérateur
begin
// si il y avait un chiffre en attente, on le sauve dans infix
if giap<>'' then
begin
infix[l_base].priorite:=6;
infix[l_base].texte:=giap;
giap:='';
l_base:=l_base+1;
end;
// on sauve l'opérateur dans infix
infix[l_base].priorite:=g_priorite[gisp[l_indice]];
infix[l_base].texte:=gisp[l_indice];
l_base:=l_base+1;
end;

// au dernier tour, si il y a un nombre en attente dans gaip, on le sauve dans infix
if (giap<>'') and (l_indice=length(gisp)) then
begin
infix[l_base].priorite:=6;
infix[l_base].texte:=giap;
l_base:=l_base+1;
end;
end;

l_pile[0].texte:='%';
l_pile[0].priorite:=1;
lip:=0;
lpp:=0;
giap:='';
g_postfix[0]:='';
FOR l_indice:=0 TO l_base-1 do
Begin
if l_pile[lip].priorite>infix[l_indice].priorite then
while l_pile[lip].priorite>=infix[l_indice].priorite do
begin
g_postfix[lpp]:=l_pile[lip].texte;
lip:=lip-1;
lpp:=lpp+1;
end;
lip:=lip+1;
l_pile[lip].texte:=infix[l_indice].texte;
l_pile[lip].priorite:=infix[l_indice].priorite;
end;
// evalue_postfix
indval:=-1;
for l_indice:=0 to lpp-1 do
begin
if (length(g_postfix[l_indice])=1) and
not (g_postfix[l_indice][1] in ['0'..'9']) then
begin
symb:=g_postfix[l_indice,1];
if (symb in ['+','-','*','/','^']) and (indval<1) then exit;
if not (symb in ['+','-','*','/','^']) and (indval<0) then exit;
case symb of
'+' : pilval[indval-1]:=pilval[indval-1]+pilval[indval];
'-' : pilval[indval-1]:=pilval[indval-1]-pilval[indval];
'*' : pilval[indval-1]:=pilval[indval-1]*pilval[indval];
'/' : pilval[indval-1]:=pilval[indval-1]/pilval[indval];
'^' : if pilval[indval-1]>0
then pilval[indval-1]:=exp(pilval[indval]*ln(pilval[indval-1]))
else pilval[indval-1]:=1;
's' : pilval[indval]:=sin(pilval[indval]); {sin}
'c' : pilval[indval]:=cos(pilval[indval]); {cos}
't' : pilval[indval]:=tan(pilval[indval]); {tan}
'l' : pilval[indval]:=log10(pilval[indval]); {log}
'r' : pilval[indval]:=arcsin(pilval[indval]); {arcsin}
'm' : pilval[indval]:=arccos(pilval[indval]); {arccos}
'n' : pilval[indval]:=arctan(pilval[indval]); {arctan}
'o' : pilval[indval]:=ln(pilval[indval]); {ln}
'p' : pilval[indval]:=exp(pilval[indval]); {exp}
'q' : pilval[indval]:=sqrt(pilval[indval]); {racine carré}
end;

// opérateur à 2 opérandes
if symb in['+','-','*','/','^'] then dec(indval);
end else
begin
inc(indval);
pilval[indval]:=StrToFloat(g_postfix[l_indice]);
end;
end;
Evalu_exp:=pilval[0];
end;
Oniria
Messages postés
296
Date d'inscription
dimanche 14 mars 2004
Statut
Membre
Dernière intervention
18 décembre 2014
2
Bonjour,

J'avais fait des essais mais sur des fonctions plus complexe que 1+Pi. les fonctions sinus, cosinus, ... s'utilise souvent avec des parenthèses : en effet, sin60 et plus rare que sin(60).
Mais c'est vrai, il y avait bien des bugs. C'est vraiment sympa de me les avoir dis car je ne les avais pas vu.
J'espère qu'il n'y a plus rien. En effet, cette fonction est aussi utilisée dans mon source d'oscilloscope pour faire des calculs entre voies de mesures. Que je vais devoir mettre à jour même s'il n'interresse pas grand monde. Pourtant, c'est une mine de calcul mathématiques : calcul de chaine mathématique, tout ce qu'il faut pour le traitement du signal etc...

En tout cas, merci
kevinou55
Messages postés
15
Date d'inscription
mardi 5 juin 2007
Statut
Membre
Dernière intervention
12 février 2008

troisieme modif ;)

en fait c'est la meme que la premiere, mais ce coup-ci c'est ta boucle après le changement des sin,soc,tan en caractères ASCII qu'il faut modifier.
Remplacer i>=Length par i>Length car tu oublie le dernier caractère. alors je ne sais pas comment elle faisait pour fonctionner avant mais quand j'ai apporté quelques modif pour un prog perso ba... ca a planté lol

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.