• Aucun résultat trouvé

Les procédures et les fonctions

Dans le document Calcul mathématique avec Sage (Page 68-71)

3.2 Algorithmique

3.2.3 Les procédures et les fonctions

Syntaxe générale. Comme bien d’autres langages informatiques, Sage permet à l’utilisateur de définir des fonctions ou des instructions sur mesure. La commande defdont la syntaxe est détaillée ci-dessous autorise la définition de procédures et de fonctions, c’est-à-dire de sous-programmes (respectivement qui ne renvoient pas de résultat et qui en renvoient un), avec un ou plusieurs arguments. Ce premier exemple définit la fonction (x, y) 7→ x2+ y2:

sage: def fct2 (x, y): ....: return x^2 + y^2

sage: a = var('a')

5*a^2

L’évaluation de la fonction se termine par la commande return dont l’argument, ici x2+ y2, est le résultat de la fonction.

Une procédure est définie de la même façon sans renvoyer explicitement de résultat, et en l’absence de l’instruction return le bloc d’instructions définissant le programme est évalué jusqu’au bout. En fait la procédure renvoie la valeur Nonequi veut bien dire ce qu’elle veut dire.

Par défaut, Sage considère que toutes les variables intervenant dans une fonction sont locales. Ces variables sont créées à chaque appel de la fonction, détruites à la fin, et sont indépendantes d’autres variables de même nom pouvant déjà exister. Les variables globales ne sont pas modifiées par l’évaluation d’une fonction ayant des variables locales du même nom :

sage: def essai (u): ....: t = u^2 ....: return t*(t+1)

sage: t = 1 ; u = 2

sage: essai(3), t, u (90, 1, 2)

Pour modifier une variable globale depuis une fonction, il faut la déclarer explici- tement grâce au mot-clé global :

sage: a = b = 1

sage: def f(): global a; a = b = 2

sage: f(); a, b (2, 1)

L’exemple suivant reprend le calcul de la moyenne arithmético-harmonique de deux nombres supposés strictement positifs :

sage: def MoyAH (u, v):

....: u, v = min(u, v), max(u, v) ....: while v-u > 2.0e-8:

....: u, v = 2*u*v/(u+v), (u+v)/2 ....: return (u+v) / 2

sage: MoyAH (1., 2.) 1.41421...

sage: MoyAH # correspond à une fonction

<function MoyAH at ...>

La fonction MoyAH comporte deux paramètres notés u et v qui sont des variables locales dont les valeurs initiales sont fixées lors de l’appel de cette fonction ; par exemple MoyAH(1., 2.) débute l’exécution de cette fonction avec les valeurs 1. et 2. des variables u et v.

La programmation structurée conseille de définir une fonction de façon à ce que return soit la dernière instruction du bloc de celle-ci. Placée au milieu du bloc d’instructions d’une fonction, cette commande return termine l’exécution

de la fonction en interrompant avant la fin l’évaluation complète de ce bloc ; en outre il peut y en avoir plusieurs dans différentes branches des tests.

La traduction informatique de l’état d’esprit des mathématiques suggère de programmer des fonctions renvoyant chacune un résultat à partir de leurs arguments, plutôt que des procédures affichant ces résultats par une commande print. Le système de calcul formel Sage repose d’ailleurs sur de très nombreuses fonctions, par exemple exp ou solve, qui renvoient toutes un résultat, par exemple un nombre, une expression, une liste de solutions, etc.

Méthode itérative et méthode récursive. Une fonction définie par l’utilisa- teur est construite comme une suite d’instructions. Une fonction est dite récursive lorsque son évaluation nécessite dans certains cas d’exécuter cette même fonction avec d’autres paramètres. La suite factorielle (n!)n∈N en est un exemple simple :

0! = 1, (n + 1)! = (n + 1) n! pour tout n ∈ N.

Les deux fonctions suivantes aboutissent au même résultat à partir d’un argument entier naturel n ; la première fonction utilise la méthode itérative avec une boucle for, et la seconde la méthode récursive traduisant mot pour mot la définition récurrente précédente :

sage: def fact1 (n): ....: res = 1

....: for kin [1..n]: res = res*k ....: returnres

sage: def fact2 (n):

....: if n == 0:return 1 ....: else:return n*fact2(n-1)

La suite de Fibonacci est une suite récurrente d’ordre 2 car la valeur de un+2 dépend uniquement de celles de un et de un+1:

u0= 0, u1= 1, un+2= un+1+ un pour tout n ∈ N.

La fonction fib1 ci-dessous applique une méthode de calcul itératif des termes de la suite de Fibonacci en utilisant deux variables intermédiaires U et V pour mémoriser les deux valeurs précédentes de la suite avant de passer au terme suivant :

sage: def fib1 (n):

....: if n == 0or n == 1:return n ....: else:

....: U = 0 ; V = 1 # les termes initiaux u0 et u1

....: for kin [2..n]: W = U+V ; U = V ; V = W ....: return V

sage: fib1(8) 21

La boucle applique à partir de n = 2 la relation un= un−1+ un−2. Par ailleurs l’affectation parallèle U,V = V,U+V à la place de W=U+V ; U=V ; V=W évite l’utilisa- tion de la variable W et traduit l’itération de la suite vectorielle Xn= (un, un+1) récurrente d’ordre 1 définie par Xn+1= f(Xn) quand f(a, b) = (b, a + b). Ces méthodes itératives sont efficaces mais leur programmation doit transformer la définition de la suite de façon à l’adapter aux manipulations des variables.

Au contraire la fonction récursive fib2 suit de beaucoup plus près la dé- finition mathématique de cette suite, ce qui facilite sa programmation et sa compréhension :

sage: def fib2 (n):

....: if 0 <= n <= 1:return n # pour n = 0 ou n = 1

....: else:returnfib2(n-1) + fib2(n-2)

Le résultat de cette fonction est la valeur renvoyée par l’instruction conditionnelle : 0 et 1 respectivement pour n = 0 et n = 1, et la somme fib2(n-1)+fib2(n-2) sinon ; chaque branche du test comporte une instruction return.

Cette méthode est cependant moins efficace car beaucoup de calculs sont inutilement répétés. Par exemple fib2(5) évalue fib2(3) et fib2(4) qui sont eux aussi calculés de la même manière. Ainsi Sage évalue deux fois fib2(3) et trois fois fib2(2). Ce processus se termine lors de l’évaluation de fib2(0) ou de fib2(1), de valeur 0 ou 1, et l’évaluation de fib2(n) consiste à calculer finalement

un en additionnant un uns et un−1 zéros. Le nombre total d’additions effectuées pour déterminer un est donc égal à un+1− 1 ; ce nombre est considérable et croît très rapidement. Aucun ordinateur, aussi rapide soit-il, ne peut calculer de cette manière u100.

D’autres méthodes sont aussi possibles, par exemple mémoriser les calculs intermédiaires grâce au décorateur @cached_function, ou exploiter une propriété des puissances de matrices : le paragraphe suivant sur l’exponentiation rapide montre comment calculer le millionième terme de cette suite.

Dans le document Calcul mathématique avec Sage (Page 68-71)

Documents relatifs