Suivez-nous sur X

|
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
ALL
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
A propos d'Obligement
|
|
David Brunet
|
|
|
|
Programmation : C - Évaluateur de fonctions
(Article écrit par Randy Finch et extrait du Randy Finch's Web Site - octobre 1989)
|
|
Voici un article qui décrit un programme C pour évaluer des fonctions 3D définies par l'utilisateur
de la forme Z=f(X,Y) en utilisant des valeurs de X et Y sélectionnables par l'utilisateur.
En convertissant un programme de traçage de fonctions 3D de BASIC en C, j'ai réalisé que je devais
écrire une routine d'évaluation de fonctions similaire à celle d'un tableur. Pour tracer différentes
fonctions dans la version BASIC du programme, il est possible d'arrêter le programme, de modifier
la fonction, puis de relancer le programme. Dans un langage compilé comme le C, ce n'est pas possible.
J'avais besoin d'une routine C qui accepterait une fonction mathématique comme entrée de chaîne de
caractères, puis évaluerait la fonction à différentes valeurs de variables. Après avoir pris connaissance
d'un programme Modula-2 démontrant cette technique dans le livre "Software Engineering With Modula-2 And
Ada" de Weiner et Sincovec (John Wiley & Sons, Inc., 1984), j'ai commencé à écrire une routine similaire
mais plus étendue en C.
Note : afin d'éviter les conflits de terminologie lorsqu'il est question de fonctions C et de
fonctions mathématiques, les fonctions mathématiques seront ci-après appelées équations.
La routine qui résulte de mes efforts se compose de deux fonctions accessibles de l'extérieur et de
nombreuses fonctions de soutien statiques. Toutes ces fonctions se trouvent dans un fichier intitulé
FUNCEVAL.C et sont présentées dans le listing 1.
Les deux fonctions accessibles de l'extérieur sont
appelées "Convert" et "Evaluate". Convert transforme une chaîne contenant une équation mathématique en
notation standard avec deux variables, X et Y, en une autre chaîne dont la notation peut être évaluée
plus rapidement et plus efficacement. Evaluate accepte deux nombres à virgule flottante en double précision
et renvoie la valeur de l'équation après avoir substitué ces deux valeurs à X et Y.
La fonction Convert se trouve vers la fin du listing 1.
Le paramètre "FunctionString" est un pointeur
vers une chaîne de caractères non signés à terminaison nulle. Cette chaîne doit contenir une équation
mathématique dans deux variables, X et Y, et peut contenir l'un des nombreux appels de fonctions transcendantales
et autres, tels que SIN, LN, SQRT, etc. Une liste complète des appels de fonction et des opérateurs mathématiques
acceptables est présentée dans le tableau 1.
FunctionString doit être en notation mathématique standard,
comme l'illustre l'équation suivante.
-12.5 + SIN(X^2) / COS(LN(Y) + 2.2e-1)
|
FunctionString peut contenir un nombre quelconque d'espaces et les caractères alphabétiques utilisés
pour les noms de fonctions et de variables qui peuvent être en majuscules ou en minuscules. Les deux
premières fonctions d'assistance appelées par Convert, RemoveSpaces et strupr, suppriment tous les
espaces de la chaîne et convertissent toutes les lettres minuscules en majuscules.
La fonction suivante appelée par Convert, CheckSyntax, examine la syntaxe de FunctionString. CheckSyntax
peut détecter 12 erreurs syntaxiques différentes, telles que des caractères illégaux, des opérateurs
mal placés et des parenthèses manquantes. Ces erreurs sont définies symboliquement dans le fichier d'en-tête
SYNTXERR.H présenté dans le listing 2.
Si une erreur est détectée, la variable globale SyntaxErr
accessible de l'extérieur est assimilée à une valeur d'erreur appropriée et un pointeur vers le caractère
incriminé dans FunctionString est renvoyé. Si aucune erreur n'est trouvée, SyntaxErr prend la valeur
FALSE et un zéro est renvoyé.
Une fois que FunctionString a passé le contrôle syntaxique, elle est copiée dans une autre chaîne, fstr.
Cela permet de conserver la forme originale de l'équation (sans espaces et avec tous les caractères alphabétiques
en majuscules) dans FunctionString pendant que des modifications sont apportées à la copie dans fstr.
La première modification de fstr est effectuée par la fonction de gestion ConvertConstants. Cette fonction
recherche initialement dans fstr les plus et les moins unaires et place un zéro devant le signe. Cette
action facilitera le traitement ultérieur de la chaîne. Ensuite, ConvertConstants analyse à nouveau fstr
en remplaçant toutes les constantes numériques par un symbole d'un octet compris entre 128 et 255 et
en plaçant la valeur réelle de la constante dans un tableau pour référence ultérieure. Le nombre maximum
de constantes autorisées dans la chaîne est de 128. Si fstr contient plus de 128 constantes, SyntaxErr
est défini à TOOMANYCONSTS et FALSE est retourné, sinon TRUE est retourné.
La fonction suivante appelée par Convert, ConvertFunctions, analyse fstr et remplace tous les noms de fonctions
transcendantales et autres par un symbole d'un octet compris entre 1 et 13. Ces symboles sont définis au
début de FUNCEVAL.C. Aucune vérification d'erreur n'est nécessaire dans cette fonction car les fonctions
illégales auront déjà été détectées dans CheckSyntax. Par conséquent, ConvertFunctions est une fonction nulle.
La dernière fonction de gestion appelée par Convert, InfixToPostfix, convertit fstr, qui est toujours en
notation mathématique standard (avec des constantes et des noms de fonctions substitués par des symboles
d'un octet), en une notation postfixe ou polonaise inverse. C'est la notation utilisée par le langage
informatique Forth et par les calculatrices Hewlett-Packard. InfixToPostfix est une fonction relativement
complexe qui lit la chaîne fstr caractère par caractère et, en fonction de la précédence des opérateurs,
place le caractère dans la chaîne globale statique NewExpr ou le place sur une pile pour un traitement
ultérieur. Si, au cours du traitement, la pile est débordée ou non, SyntaxErr sera assimilé à STACKUNDERFLOW
ou STACKOVERFLOW et FALSE sera renvoyé. Lorsque le traitement est terminé, NewExpr contient l'équation
mathématique en notation postfixe et renvoie TRUE.
Les fonctions Convert et ConvertConstants comportent plusieurs lignes de code qui ne seront compilées
que si le symbole DEBUG est défini. Ces sections de code imprimeront l'équation à différents moments
de son traitement. Examinons un exemple étape par étape. Supposons que la fonction telle qu'elle a été
saisie à l'origine par l'utilisateur soit la suivante :
2.1E-1 + x*y - sin(-.8*X) / ln(+Y + 100)
|
Les étapes suivantes permettront de convertir cette fonction en forme symbolique avec la notation
postfixe. La fonction de gestion qui accomplit chaque étape apparaît entre parenthèses.
- Étape 1. Supprime tous les espaces (RemoveSpaces).
2.1E-1+x*y-sin(-.8*X)/ln(+Y+100)
|
- Étape 2. Convertis les lettres minuscules en majuscules (strupr).
2.1E-1+X*Y-SIN(-.8*X)/LN(+Y+100)
|
- Étape 3 : Vérifie la syntaxe. Si aucune erreur n'est détectée, le traitement se poursuit.
Aucune modification n'est apportée à la chaîne de caractères (CheckSyntax).
- Étape 4A. Mets des zéros devant les plus et les moins unaires (ConvertConstants).
2.1E-1+X*Y-SIN(0-.8*X)/LN(0+Y+100)
|
- Étape 4B. Remplace les constantes par des symboles d'un octet compris entre 128 et 255.
Étant donné qu'il s'agit de caractères non imprimables, chaque caractère de la chaîne
sera affiché ci-dessous sous forme de valeur décimale. Le caractère ou la constante
qu'il représente apparaît sous la valeur décimale (ConvertConstants).
128 43 88 42 89 45 83 73 78 40 129 45 130 42 88
2.1E-1 + X * Y - S I N ( 0 - .8 * X
41 47 76 78 40 131 43 89 43 132 41
) / L N ( 0 + Y + 100 )
|
- Étape 5. Remplace les noms de fonctions par des symboles d'un octet compris entre 1 et 13 (ConvertFunctions).
128 43 88 42 89 45 1 40 129 45 130 42 88 41
2.1E-1 + X * Y - SIN ( 0 - .8 * X )
47 12 40 131 43 89 43 132 41
/ LN ( 0 + Y + 100 )
|
- Étape 6. Convertis la chaîne de caractères en notation postfixe (InfixToPostfix).
128 88 89 42 43 129 130 88 42 45 1 131 89 43
2.1E-1 X Y * + 0 .8 X * - SIN 0 Y +
132 43 12 47 45
100 + LN / -
|
La forme finale de l'équation de l'étape 6 réside dans la chaîne NewExpr. Un pointeur vers cette
chaîne est renvoyé par Convert.
La fonction Evaluate, à la fin du listing 1,
peut être utilisée pour évaluer l'équation à différentes
valeurs de X et Y. Comme l'équation est maintenant en notation postfixe, Evaluate est une routine plutôt
simple. Elle lit simplement les caractères de NewExpr de manière séquentielle ; si un caractère représente
X, Y, ou une constante, sa valeur numérique réelle est poussée sur une pile. Si un caractère représente
une fonction, Evaluate transmet le nombre en haut de la pile ainsi que le symbole du caractère représentant
la fonction à la fonction Calculate. Le résultat de l'application de cette fonction au nombre sera renvoyé.
Par exemple, si le nombre est égal à 100 et que la fonction est LOG, une valeur de 2 sera renvoyée.
Cette valeur de retour est ensuite placée en haut de la pile.
Si un caractère représente un opérateur (^, +, -, *, /), les deux premiers chiffres de la pile et
le symbole de l'opérateur sont transmis à Calculate. Le résultat de l'opération effectuée sur les deux
nombres est renvoyé. Par exemple, si le nombre en haut de la pile est 24, que le nombre suivant sur
la pile est 12 et que l'opérateur est "/", Calculate renvoie 12/24 ou 0,5. Notez que l'opération est
toujours effectuée dans l'ordre suivant :
(Deuxième chiffre de la pile) opérateur (Premier chiffre de la pile)
|
La procédure ci-dessus se poursuit jusqu'à ce qu'il ne reste plus de caractères à lire dans NewExpr.
À ce stade, la valeur de l'équation à laquelle ont été substituées les valeurs appropriées de X et Y
se trouve sur le dessus de la pile. Cette valeur est retournée par Evaluate. Veuillez noter que Evaluate
ne vérifie pas les opérations mathématiques illégales telles que la racine carrée d'un nombre négatif
ou une multiplication qui provoque un débordement. La méthode de traitement de ces types d'erreurs varie
selon les compilateurs. Il est laissé au lecteur le soin d'ajouter cette forme de gestion des erreurs si
elle est nécessaire.
Un programme intitulé TESTFEVL.C est présenté dans le listing 3.
Ce programme teste les fonctions Convert
et Evaluate. L'utilisateur peut saisir une équation mathématique (jusqu'à 255 caractères) ainsi que les
valeurs de X et Y ; le programme affichera le résultat de l'évaluation de l'équation. Malheureusement,
la fonction "scanf" (de la bibliothèque C) ne permet pas de saisir des espaces dans une chaîne de caractères
(ils sont utilisés comme délimiteurs) ; par conséquent, vous ne pourrez pas voir la fonction RemoveSpaces
en action (remarque : si des espaces sont saisis comme partie de l'équation, le programme se comportera
de manière erratique car les caractères après les espaces sont utilisés comme entrée pour les appels
scanf ultérieurs). Si vous compilez FUNCEVAL.C avec "DEBUG" défini, chaque étape de la conversion de
l'équation sera affichée sur la sortie standard. Vous pouvez jouer à votre guise. Assurez-vous de taper
des équations syntaxiquement incorrectes pour voir comment fonctionne la détection des erreurs. L'équation
sera affichée, une flèche vers le haut apparaîtra sous le caractère fautif, et un message d'erreur approprié
sera imprimé.
FUNCEVAL.C et TESTFEVL.C sont écrits de manière générique et ont été compilés, liés et exécutés avec
succès sur un Amiga 1000 utilisant Lattice C v4.01 et v5.02, sur un IBM AT utilisant Microsoft C v4.0,
et sur un superordinateur Cray X-M/P utilisant le compilateur Cray (avec une modification). Si vous
utilisez un compilateur C plus ancien, certaines des fonctions de la bibliothèque standard utilisées
dans ce programme peuvent ne pas être disponibles.
|