CALCULATRICE DE CHAINES MATHÉMATIQUES

HAFTARIFOUAD Messages postés 256 Date d'inscription mercredi 5 septembre 2007 Statut Membre Dernière intervention 6 janvier 2011 - 28 janv. 2008 à 16:03
kevinou55 Messages postés 15 Date d'inscription mardi 5 juin 2007 Statut Membre Dernière intervention 12 février 2008 - 12 févr. 2008 à 11:20
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/45537-calculatrice-de-chaines-mathematiques

kevinou55 Messages postés 15 Date d'inscription mardi 5 juin 2007 Statut Membre Dernière intervention 12 février 2008
12 févr. 2008 à 11:20
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 292 Date d'inscription dimanche 14 mars 2004 Statut Membre Dernière intervention 18 décembre 2014 3
7 févr. 2008 à 21:58
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 220 Date d'inscription lundi 30 octobre 2000 Statut Membre Dernière intervention 15 juillet 2013
7 févr. 2008 à 11:34
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 292 Date d'inscription dimanche 14 mars 2004 Statut Membre Dernière intervention 18 décembre 2014 3
31 janv. 2008 à 20:03
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
31 janv. 2008 à 10:22
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
Oniria Messages postés 292 Date d'inscription dimanche 14 mars 2004 Statut Membre Dernière intervention 18 décembre 2014 3
30 janv. 2008 à 22:52
Merci de regarder le source, c'est sympa.
Je vais regarder tout ça demain et je mettrais une correction rapidement.

A demain
kevinou55 Messages postés 15 Date d'inscription mardi 5 juin 2007 Statut Membre Dernière intervention 12 février 2008
30 janv. 2008 à 17:02
deuxieme modif lol:
au debut de la fonction evalue_exp
Le deuxieme if : "if ( (i>1) and ( (chn[i-1]<'0') or (chn[i-1]>'9') ) and (chn[i]='-'))"
il faut rajouter la condition "and chn[i-1]<>'E'"
car sinon ca fait un bug sur les 10^negatif tu te retrouve avec deux signes "-"

ps: désolé pour les noms de variable je les ai modifiés
kevinou55 Messages postés 15 Date d'inscription mardi 5 juin 2007 Statut Membre Dernière intervention 12 février 2008
30 janv. 2008 à 14:37
Petite modif a apporter:

avant de remplacer chaque operateur du genre sin,cos,tan par des caracteres ascii, il faut modifier la condition d'arret de la boucle Repeat Until
en effet il faut mettre i>Length a la place de i>=Length car sinon le drnier caractère n'est pas pris en compte.
donc si onutilie PI en dernier bah il ne sera as pris en compte...

très bonne source sinon malgré un manque de commentaires... ;)
cs_jeanr Messages postés 17 Date d'inscription vendredi 25 avril 2003 Statut Membre Dernière intervention 12 juin 2008
29 janv. 2008 à 07:22
Bon source :-)
Oniria Messages postés 292 Date d'inscription dimanche 14 mars 2004 Statut Membre Dernière intervention 18 décembre 2014 3
28 janv. 2008 à 16:08
Bonjour,

Merci beaucoup, et toi de même...
HAFTARIFOUAD Messages postés 256 Date d'inscription mercredi 5 septembre 2007 Statut Membre Dernière intervention 6 janvier 2011
28 janv. 2008 à 16:03
Salut ;-)

Trés bon votre code
Voilà je veux juste vous souhaiter bonne continuation.