home *** CD-ROM | disk | FTP | other *** search
-
- ==========================================================================
- APPRENTISSAGE du C version ALB_10
-
- CHAPITRE 6: DES FONCTIONS.
- ==========================================================================
-
-
-
- Pourquoi avoir inventé les fonctions?
- Pour des raisons pragmatiques: elles sont utiles au programmeur!
-
-
- 1° Nous avons déjà plusieurs fois utilisé des fonctions dans le chapitre
- précédent pour éviter la répétition d'une même séquence de code.
-
- 2° Reprenez maintenant, dans le même chapitre, le menu du programme de
- calcul de diverses lois de distribution de probabilités: CH05_06.C.
- Chaque possibilité du switch renvoie: " Lancement de la fonction ..."
- Dans le programme complet, les lettres N, S, K, F, renvoient chacune à un
- sous-programme de calcul, contenu dans une fonction. L'intérêt est que
- chaque fonction est parfaitement isolée. Si un jour il faut en modifier
- une seule, nous pourrons le faire sans risque pour les autres.
- Cela renforce la sécurité du code.
-
- 3° Cela permet de rendre aussi beaucoup plus claire la structure d'un
- programme et sa lisibilité.
-
- 4° Pour résumer: c'est la possibilité de fractionner les grosses choses
- complexes en petits trucs simples qu'ont peut résoudre et gérer un par un.
- Nous restons dans la tradition de la méthode scientifique.
-
-
- Ce langage s'est développé en fonction
- des besoins de ceux qui l'utilisaient.
- Chapitre 6: Des fonctions page 1
-
-
-
-
- 1. REGLES D'UTILISATION.
- ===========================
-
-
- 1.1 Premier exemple ( passage par "valeur").
- --------------------------------------------
-
- ************
- Examinez le programme: CH06_01.C
- ************
- Ce programme permet de faire deux fois la saisie d'un caractère, sa
- conversion en majuscule s'il ne l'est déjà, puis son affichage. Il y a
- trois actions auxquelles correspondent trois fonctions.
-
- 1° Les trois fonctions sont déclarées dans l'en tête, au même titre que la
- bibliothèque utilisée. Ce sont les "prototypes" des trois fonctions:
-
- char LitChar( void);
- char Min_Maj( char);
- void EcritChar( char);
-
- Nous déclarons au compilateur les éléments indispensables pour identifier
- la fonction au moment où le programme l'appellera. La définition de la
- fonction, sa structure interne, nous l'écrirons après le corps de main()
- la fonction principale.
-
- Quels sont les éléments nécessaires à la déclaration de la fonction?
-
- * Son type, char pour les deux premières, c'est le type de la valeur
- de retour. Il est unique. La troisième ne renvoie rien, son type
- est donc void.
- * Son nom.
- * La liste des types des arguments qu'on passe à la fonction pour
- qu'elle puisse travailler. Si on ne passe rien on écrit void.
- * Un point-virgule clôt la déclaration.
-
- => Deux fonctions qui ne diffèrent que par le type de la valeur de retour
- sont considérées comme identiques par le compilateur qui renverra alors
- un message d'erreur. Il ne fera pas de différence entre:
-
- char LitChar( void) et void LitChar( void). Il vous dira en général
- que vous avez fait une erreur de type dans la déclaration.
- Il ne se sert du type de la fonction que pour contrôler si dans le
- main() vous demandez bien le même type en retour.
-
- car1= LitChar(); la fonction renvoie t'elle bien une variable du
- type de car1 ou d'un type équivalent?
-
- => Notez qu'il est parfois utile pour des raisons de clarté d'ajouter à
- la déclaration le nom des arguments qui sont passés. On peut déclarer
- bien que le compilateur n'en ait pas besoin:
-
- char Min_Maj( char c1); au lieu de:
- char Min_Maj( char);
- Chapitre 6: Des fonctions page 2
-
-
-
- 2° Les fonctions sont définies plus loin, après le corps de main().
- Il est permis, mais pas conseillé, de le faire dans l'en-tête:
-
- char Min_Maj( char c1) // pas de point-virgule
- {
- le corps de la fonction
- } // une accolade clôt la définition.
-
- 3° Le compilateur lit ensuite le corps de la fonction main(). Il contrôle
- au passage la conformité au type de l'appel à la fonction.
-
- 4° car2= Min_Maj( car2); Que se passe t'il en réalité?
-
- On dit que le C passe la VALEUR de la variable car2 à la fonction
- Min_Maj(). En réalité, le programme copie la VALEUR de la variable car2
- et l'affecte à la variable c1 qui figure dans la définition de la fonction
- entre les parenthèses et qui est générée à chaque appel de la fonction
- sans que nous ayons besoin de la déclarer formellement.
- La variable car2 n'est pas utilisée. La fonction accomplit son travail
- avec c1 et retourne une VALEUR qui est alors affectée à car2.
- La variable intermédiaire c1 est alors détruite. En gros:
-
- car2 existe
- appel à la fonction Min_Maj( char c1)
- création automatique de c1
- affectation à c1 de la VALEUR de car2
- exécution de la fonction avec c1
- retour d'une VALEUR
- affectation de cette valeur à car2 qui est alors modifiée
- destruction de c1
-
- On dit qu'on a fait un passage par "valeur" à la fonction. Quand il n'y
- a pas d'argument à passer, on met entre les parenthèses le mot void.
-
- 5° Return( évaluation d'une expression);
-
- Dans la première fonction LitChar(), le programme retourne la VALEUR de
- l'expression c0 qui est entre parenthèses ( elles ne sont pas obligatoires
- mais rendent souvent le programme plus facile à lire). Il ne faut pas
- oublier le point-virgule.
- L'exécution de la fonction est arrêtée après le renvoie de la valeur.
- Notez que les while(...); n'ont pas de corps.
-
- 6° Notez qu'on peut toujours appeler une fonction à partir d'une autre
- ( la fonction principale main() est aussi une fonction).
- Elle peut se placer n'importe où dans la fonction mais ne renvoie qu'une
- seule valeur qui est nécessairement du type de la fonction.
- La fonction Min_Maj() utilise return à deux endroits. L'instruction
- if-else est interrompue, la fonction est arrêtée et la valeur d'une des
- deux expressions est renvoyée.
-
- Dans EcritChar(), la fonction ne renvoie rien. On peut ne pas utiliser
- return. L'accolade fermante suffit pour indiquer la condition de fin du
- bloc. Le contrôle est alors rendu au point d'appel de la fonction sans
- qu'il y ait un retour d'information. On conseille parfois d'utiliser une
- instruction return sans argument pour rendre le code plus clair et
- faciliter des modifications futures. Ce n'est pas indispensable car de
- toutes façons, le compilateur ajoute systématiquement un return à la fin
- d'une fonction.
- Chapitre 6: Des fonctions page 3
-
-
-
- 1.2 Passage par "pointeur".
- ---------------------------
- La technique du passage par valeur ne permet de modifier, de manipuler,
- qu'une seule variable extérieure à la fonction en utilisant l'instruction
- return.
- Or, les programmeurs avaient besoin de manipuler, par une même fonction,
- plusieurs variables extérieures à la fonction.
- La solution fut trouvée par un rapprochement avec une application des
- opérateurs unaires de référencement qui permettent d'obtenir l'adresse
- d'une variable et les opérateurs de déréférencement qui permettent d'agir
- sur une variable à partir de son adresse ( chapitre 3: 5.5).
- La variable déréférencée est appelée un pointeur.
-
- A titre d'exercice et pour voir le mécanisme de l'utilisation des
- pointeurs nous allons reprendre le programme précédent, en ne touchant pas
- les fonctions que nous venons d'utiliser pour manipuler la variable car1,
- mais en créant 3 nouvelles fonctions qui manipuleront car2 avec le même
- résultat, mais en utilisant le passage par pointeur.
- Puis nous étudieront un programme moins simple qui permet de manipuler
- plusieurs variables dans la même fonction.
-
- ************
- 1.2.1. Analyse du programme: CH06_02.C
- ************
-
- 1° Examinons la déclaration, le prototype de la fonction LitChar2:
-
- void LitChar0( char*);
-
- => void signifie qu'elle ne renvoie rien.
- => entre les parenthèses, char* signifie qu'elle utilise un pointeur
- sur une variable caractère. Le passage de l'information du programme
- principal à la fonction se fera par un pointeur.
-
- 2° Examinons maintenant la définition de la fonction LitChar0.
-
- void LitChar0( char *c0) { ... }
-
- => tout se passe comme si la fonction créait une variable c0, pour
- recevoir l'ADRESSE de la variable car0 du programme principal,
- celle qu'il faudra manipuler.
- La valeur déréférencée *c0 sera celle de la variable car0.
- Toute modification de *c0 modifiera car0.
- On dit que le pointeur *c0 pointe car0.
-
- Souvenez vous ( chapitre 3: 5.5):
-
- =================================================================
- | si: b= &a; alors: *b= a; |
- =================================================================
- c0= &car0; alors: *c0= car0;
-
- 3° Nous n'avons plus besoin de l'instruction return. L'acquisition et
- l'affectation du caractère se sont fait à l'intérieur du premier while
- avec l'instruction, c0= getchar().
- Chapitre 6: Des fonctions page 4
-
-
-
- 4° Revenons dans la fonction principale pour examiner l'appel de la
- fonction:
- LitChar( &car0);
-
- La fonction utilise un pointeur, elle attend donc une adresse: &car0.
-
- 5° Examinez aussi les changements dans les deux autres fonctions. Elles
- s'analysent suivant les mêmes principes.
-
- ************
- 1.2.2. Analyse du programme: CH06_03.C
- ************
-
- Nous reprenons ici le code de Thad Smith pour calculer des combinaisons
- avec des nombres réels doubles. La fonction utilise à la fois le passage
- par valeur pour initialiser la variable "test" et le passage par pointeur
- pour initialiser la variable cnm0.
- Dans cet exemple on ne manipule par pointeur qu'une seule variable, mais
- pour une application qui nécessiterait la manipulation de plusieurs autres
- variables, la technique resterait la même.
-
- 1° Nous utilisons la directive #define pour définir une constante égale
- au maximun du domaine des doubles.
-
- 2° Le prototype de la fonction nous indique qu'elle renvoie un int,
- qu'elle demande deux int passés par valeur et utilise une fois le
- passage par un pointeur.
-
- 3° Vous reconnaîtrez le coeur du code de Thad. Nous avons seulement ajouté
- trois possibilités de sortie de la fonction en utilisant chaque fois
- l'instruction return:
- return -1; quand les paramètres n et m ne sont pas conformes;
- return 1; quand le calcul va sortir du domaine des doubles;
- return 0; quand tout s'est bien passé.
- La fonction renvoie donc une information qui nous renseigne sur la
- manière dont elle a fonctionné.
-
- Cette information est renvoyée dans notre programme à la variable test,
- Ce qui explique que dans main() nous trouvions:
- test= Combinaisons(...);
-
- 4° Examinons dans le programme principal l'appel de la fonction:
-
- test= Combinaisons( n0, m0, &cnm0);
-
- Pour des raisons de clarté, nous avons choisi pour les variables de la
- fonction principale des noms proches de ceux qui sont utilisés dans la
- fonction Combinaisons().
- La fonction crée au moment de l'appel les variables n et m et leur
- affecte les valeurs de n0 et m0. L'adresse de cnm0 est affectée à la
- variable c qui sera manipulée par le pointeur *c qui pointe alors sur
- cnm0.
- Tout se passe comme si: c= &cnm0; donc: *c identique à cnm0;
- Chapitre 6: Des fonctions page 5
-
-
-
-
- A la clôture de la fonction:
- les variables n, m, c, cnm, i, f sont détruites.
- n0, m0, n'ont pas été modifiées car elles sont passées par valeur
- et que le return ne les concerne pas.
- test a été modifiée par le return.
- cnm0 a été passée par pointeur et a donc pu être modifiée.
-
-
- 1.3 Comparaison des vitesses d'exécution entre les deux méthodes.
- -----------------------------------------------------------------
-
- Plutôt que d'affirmer que l'une des méthodes est plus rapide que
- l'autre, nous vous proposons de faire un test que vous pourrez utiliser
- pour évaluer chaque cas en particulier.
-
- ************
- Analyse du programme: CH06_04.C
- ************
- 1° Nous avons écrit la fonction de calcul des combinaisons de deux
- manières. La première version utilise le passage par valeurs et
- retourne le nombre de combinaisons. La seconde passe ce nombre par un
- pointeur. Les fonctions vont être appelées ( d- k) fois pour calculer
- C( i, j), i diminuant de d à k avec j= i- k. Le cumul des valeurs se
- fait dans des variables somme0 et somme1. Nous avons simplifié le code
- des fonctions et pris d= 800, k= 100, soit 700 cycles.
-
- 2° Nous appelons la bibliothèque <time.h> pour pouvoir utiliser la
- fonction clock(). Cette fonction accepte pour arguments un type
- particulier de donnée clock_t. Elle nous renvoie la durée d'exécution
- depuis le début du programme en nombre de tops de l'horloge interne de
- votre machine. Le symbole utilisé par printf() est %f. CLK_TCK est une
- constante qui donne le nombre de tops de l'horloge interne par seconde.
-
- 3° Ne laissez fonctionner QUE CE PROGRAMME sur votre machine pour ne pas
- avoir à partager le processeur avec d'autres applications.
- Exécutez plusieurs fois ce programme. Qu'en pensez vous?
-
- J'ai essayé sur plusieurs machines, je dois avouer que les résultats
- n'ont pas été très concluants. Mais ma méthode est peut être à
- remettre en question!
-
- Vous pourrez noter que dans les FAQ, les développeurs américains se
- montrent très sceptiques dès qu'il s'agit d'optimiser du code.
-
- Les "auteurs" disent que:
-
- => Si le type de l'argument à passer est d'une taille plus grande que
- celle des entiers, on le passe par pointeur. (pourquoi pas!)
-
- => Si la valeur de la variable doit être modifiée par la fonction
- appelée on passe l'argument par pointeur.
- ( si nous devons modifier plusieurs variables, on ne peut pas faire
- autrement).
- Chapitre 6: Des fonctions page 6
-
-
-
-
- 2. CLASSIFICATION DES VARIABLES EN FONCTION DE LEUR PORTEE.
- ===========================================================
-
- Nous avons déjà l'habitude de classer les variables en fonction de leur
- type, char, int, double, etc.
- Nous pouvons aussi les classer en fonction de leur portée, c'est à dire
- de l'étendue du programme dans laquelle une variable est reconnue et peut
- être utilisée.
- Nous distinguerons deux catégories:
-
- les variables locales ( ou automatiques);
- les variables globales ( ou externes);
-
- 2.1. Les variables locales.
- ----------------------------
- Ce sont celles que nous avons utilisées jusqu'à présent. Elles sont
- déclarées à l'intérieur d'un bloc. Un bloc est défini par ce que l'on
- trouve entre une paire d'accolades. Leur portée est limitée à ce bloc.
- Le corps d'une fonction, principale ou non, est un bloc.
-
- Les variables locales sont stockées dans la mémoire de pile (stack)
- affectée à un programme. A l'appel d'une fonction, une zone mémoire lui
- est allouée où on trouvera l'adresse de départ du programme, la mémoire
- nécessaire à une valeur de retour, les valeurs des arguments et les
- variables locales. Au retour tout sera détruit et la zone mémoire libérée.
- Ces informations stockées dans la pile sont donc volatiles.
-
- Il faut noter que juste après leur déclaration, les variables locales
- contiennent n'importe quoi. C'est à l'initialisation qu'elles prennent la
- valeur que vous leur attribuez.
- Dans le programme précédent, n0, m0, cnm0 sont reconnues dans main()
- mais ne le sont pas dans la fonction Combinaisons(). Placez un zéro
- à la suite d'un m de cette dernière fonction et vous aurez un message
- d'erreur à la compilation.
- A la sortie de la fonction Combinaisons() ses variables locales, n, m,
- cnm, i, f, sont détruites.
- C'est aussi le cas à la fin de main() où les variables n0, m0, cnm0,
- test, sont détruites.
-
- Si on déclare des variables à l'intérieur du bloc délimité par les
- accolades d'un do {...} while(); les variables déclarées sont locales
- pour le bloc et ne sont pas reconnues à l'extérieur.
-
- Chacun chez soi. L'avantage est de garder entre les fonctions des
- barrières étanches qui évitent des mélanges aux conséquences toujours
- imprévisibles.
-
- ---------------------------------------------------------------------
- | Toujours cette préoccupation de sécurité. Il faut travailler avec |
- | des modules indépendants de façon à pouvoir modifier, maintenir |
- | les programmes sans trop de difficultés. |
- ---------------------------------------------------------------------
-
- Cette préoccupation est l'une de celles qui ont amené les développeurs à
- imaginer la "programmation orienté objet".
- Chapitre 6: Des fonctions page 7
-
-
-
- L'idéal était d'en rester là. Mais les développeurs du C avaient lu
- Ciceron et médité ses commentaires sur l'ancienne maxime du droit romain,
- "summum jus summa injuria", l'application extrême du droit est aussi
- l'extrême injustice. Il est parfois indispensable de transgresser les
- meilleurs principes.
-
- 2.2. Les variables globales.
- ----------------------------
-
- Une variable doit parfois être utilisées par plusieurs fonctions. Elle
- doit donc être définie en dehors de tout bloc, dans l'en tête du programme.
-
- Elle n'est pas stockée dans la mémoire de pile du programme mais dans
- sa mémoire statique. Nous reviendrons à la fin de ce manuel sur ces
- questions de mémoire.
-
- Les variables globales sont automatiquement initialisées à zéro au
- moment de leur déclaration quand il n'y a pas d'initialisation explicite.
- La valeur initiale doit être une constante, par exemple 4 ou 5.67e3, et
- non une expression comme ( 3* x- y).
- Elles conservent les valeurs qu'on leur affecte successivement au cours
- du programme. C'est un avantage et en même temps un danger.
-
- ************
- Examinez le programme: CH06_05.C
- ************
-
- Compilez le programme.
- Le compilateur vous renverra 5 messages d'erreur du genre "le symbole k
- n'est pas défini". Nous sommes en effet en dehors du bloc où la variable
- k a été définie. Replacez correctement les symboles /* et */ pour les
- lignes 24, 34 et 45 du code. Le programme fonctionnera normalement.
-
- Par contre la variable globale somme est accessible à partir d'un point
- quelconque du programme. Vérifiez le en plaçant des printf().
-
- Remarquez aussi que la qualification "globale" de la variable "somme"
- nous a évité des passages par valeur ou par pointeur aux fonctions.
-
-
- Quel est le danger d'utiliser des variables globales?
- -----------------------------------------------------
-
- On peut en modifier la valeur en tout point du code. Si le programme est
- complexe, la variable globale a été manipulée dans le programme principal
- et dans une série de fonctions. On ne sait plus très bien au bout d'un
- moment ce qu'elle contient. Il se produit alors des "effets de bords".
- Imaginez que vous soyez obligés de modifier le programme six mois plus
- tard! Il faudra analyser le code en détail pour s'y retrouver.
-
- Autant que possible, il faut éviter des constructions dangereuses qui
- peuvent faire apparaître des bugs latents.
- Chapitre 6: Des fonctions page 8
-
-
-
-
- 3. STATUT D'UNE VARIABLE OU D'UNE FONCTION.
- ============================================
-
- 3.1. Statut "const".
- --------------------
-
- Si on désire empêcher toute modification d'une variable, on peut lui
- donner le statut "const", que la variable soit locale ou globale. Cette
- norme est maintenant acceptée par le C ANSI.
-
- En déclarant "const" un argument passé à une fonction, on interdit de
- la même manière la modification de la VALEUR passée à la fonction. La
- variable dans la fonction principale n'est de toutes façons pas touchée.
- C'est la nouvelle variable à l'intérieur de la fonction qui ne peut plus
- être modifiée.
-
- int Calcule( const int, const int);
-
- void main(void)
- {
- int a, b, c;
- c= Calcule( a, b);
- printf(" c= %d", c);
- }
- int Calcule( const int x, const int y) { return( x* y); }
-
- Les variables a et b ne peuvent être modifiées par la fonction Calcule().
- Ce sont les VALEURS de a et de b qui ont été passées aux variables x et y.
- Le passage par valeur rend donc toute modification des variables a et b
- impossible. Si leurs valeurs ne doivent pas non plus être modifiées dans
- la fonction appelée, on donne à x et y à qui sont affectées ces valeurs,
- le statut de constantes.
-
- 3.2. Statut "extern".
- --------------------
- Nous verrons qu'une application informatique utilise plusieurs fichiers.
- On définit comme externes des variables ou des fonctions qui sont également
- définies dans un autre fichier que celui qui contient le programme. Cela
- évite de faire des doubles déclarations. Elles ne sont stockées qu'une
- seule fois en mémoire, bien que connues et manipulées par plusieurs
- fichiers. Les variables externes sont toujours globales.
-
- Les dangers évoqués au sujet des variables globales sont encore multipliés!
-
- Dans une en-tête on peut donc trouver:
- extern void Combinaisons( int, int, double *);
- extern int somme;
- Cette fonction et cette variable sont déclarés dans un autre fichier.
-
- Si l'éditeur de liens entre les fichiers objets détecte une confusion
- de nom ou de prototype entre des fonctions externes, si elle manque ou si
- elle est définie plusieurs fois, vous aurez un message d'erreur.
- Mais pour les variables externes, certains compilateurs ne s'assurent
- que de la présence d'une déclaration de la variable globale dans l'un des
- fichiers qu'ils compilent. Une confusion sur le type de cette variable ne
- sera pas détecté. Vous devrez vérifier chaque fois, que le type de la
- variable globale externe que vous utilisez est bien celui attendu dans
- votre code.
- Chapitre 6: Des fonctions page 9
-
-
-
- 3.3. Statut "static".
- ---------------------
-
- 3.3.1. Pour une variable.
-
- Quand on veut qu'une variable locale puisse être reconnue dans tout un
- fichier, on lui donne le statut de "static".
- Elles ne sont plus stockées dans la pile du programme mais dans la
- mémoire statique comme les variables globales.
-
- ************
- Calcul des termes de la série de Léonard de Pise: CH06_06.C
- ************
-
- Les variables s_moins1 et s_moins2 sont des variables locales de la
- fonction CalcTerme. Normalement elles seraient détruites à chaque
- clôture de la fonction et réinitialisées à 1 à chaque appel.
-
- Quand elles sont déclarées comme variables statiques, elles sont
- initialisées à 1 au premier appel de la fonction, elles ne sont pas
- détruites à la clôture et gardent leur valeur à l'appel suivant. Elles
- ne sont pas réinitialisées à 1, puisqu'elles se comportent désormais
- comme des variables globales à l'intérieur du fichier!
-
- Les dangers évoqués au sujet des variables
- globales sont encore multipliés!
-
-
- 3.3.2. Pour une fonction.
-
- Contrairement aux variables globales, les fonctions sont en quelque
- sorte externes par nature car on peut y accéder à partir d'autres
- fichiers. On les déclare "static" pour réduire leur accessibilité au
- fichier où elles sont déclarées.
- Chapitre 6: Des fonctions page 10
-
-
-
-
- 4. PROPRIETE DE RECURRENCE DES FONCTIONS.
- ==========================================
-
- On dit que les fonctions possèdent la propriété de récurrence car elles
- peuvent s'appeler elles mêmes. Il faut prévoir une condition d'arrêt pour
- ne pas déclencher de boucles infinies.
-
- C'est parfois très élégant.
-
- A chaque appel de la fonction, un jeu de variables locales se crée.
- Elles sont ajoutées sur la pile. Lorsque la condition d'arrêt s'exécute,
- les jeux de variables sont retirés successivement de la pile et utilisés
- par la fonction.
-
- Ce processus est donc gourmand en termes de temps
- d'exécution et d'occupation de mémoire.
-
- ************
- Calcul d'une série par récurrence: CH06_07.C
- ************
-
- 1° Nous avons contrôlé la saisie de n en empêchant l'introduction d'une
- valeur négative ou nulle. Une valeur réelle, 2.58 sera tronquée à 2.
-
- 2° La fonction SommeSerie() s'appelle elle même et la condition d'arrêt
- est que n< 0.
-
- 3° Cela fonctionne bien pour des valeurs faibles de n.
- Augmentez progressivement cette valeur. Vous aurez bientôt un message
- d'erreur: "Stack overflow" vous avez dépassé les capacités de la pile.
- La limite dépend de la taille que vous donnez à la pile sur votre
- machine. La mienne bloque à n= 327.
-
- C'est gênant.
-
- ************
- Comparez la lisibilité des 2 fonctions: CH06_08.C
- ************
-
- 1° La série qui permet de calculer directement l'arc de cercle dont la
- tangente est x s'écrit:
-
- Arc tg x= x- x^3/ 3+ x^5/ 5-...+ terme général +...
-
- Le symbole (^) signifie puissance: x^n => x à la puissance n.
-
- Le terme général est celui qui permet de représenter tous les autres,
- ici:
- terme général: X(n)= (-1)^n* x^(2*n+ 1)/( 2* n+ 1)
-
- en faisant n= 0 terme de rang 0: X(0)= x
- n= 1 terme de rang 1: X(1)= - x^3/ 3
- n= 2 terme de rang 2: X(2)= x^5/ 5 ,etc.
-
- Cette série converge très lentement. C'est à dire qu'il faut calculer
- et additionner beaucoup de termes pour avoir une précision acceptable.
- Chapitre 6: Des fonctions page 11
-
-
-
- 2° Ce n'est pas particulièrement facile mais essayez avant d'analyser
- le programme d'écrire la fonction de calcul sous deux formes:
-
- La première avec une boucle classique,
- de i= 0 à i= n j'additionne les X(i);
- La seconde en utilisant la récurrence comme précédemment.
-
- Il faut inclure la bibliothèque <math.h> car elle possède une fonction,
- pow( x, n) qui renvoie un réel double égal à x^n.
-
- A titre de contrôle sachez que Arc tg 1= 0.787873 pour 100 termes.
-
- 3° Analysons le programme. Une saisie contrôlée classique de n puis celle
- de x.
-
- 4° Dans ArcTangente1() nous avons passé arctg1 par pointeur. Il n'y a pas
- de difficultés insurmontables dans le code des fonctions.
- Que cela ne vous empêche pas de vous planter! Je vous rappelle un des
- mots favoris de Petrus Albulus," On ne progresse que par l'erreur".
-
- 5° La machine nous renvoie un message d'erreur dès que n est trop grand.
- La mienne bloque à n= 138: "Stack overflow".
- D'autre part il est peut être plus facile d'écrire ou de lire une
- fonction classique avec une boucle for.
-
- Qu'en pensez vous?
- Avez vous vraiment envie d'utiliser des fonctions récurrentes?
-
- 6° Notez qu'il existe dans math.h une fonction atan(x) qui calcule très
- bien Arctg x en utilisant une méthode beaucoup plus rapide.
- Fin du chapitre 6: Des fonctions page 12
-
-
-