mathématiques et programmation fonctionnellelivrecinq.org/math/ja2013/livretpython.pdf ·...

Post on 01-Aug-2020

2 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Mathématiques et programmation fonctionnelle

Pascal CHAUVINpascal.chauvin@ac-nantes.fr

Groupe « Environnements Interactifs et Enseignement des Mathématiques »IREM des Pays de la Loire

Journées académiques de l’IREM des Pays de la Loire

17 & 18 avril 2013

Table des matières1 L’ordinateur : un super-calculateur ! 2

2 Un jeu d’enfants... pour voir 32.1 La distributivité avec Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32.2 La distributivité avec C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42.3 La distributivité avec Objective Caml . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52.4 La distributivité avec Python : le retour ! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

3 Nombres décimaux et représentation binaire 7

4 Un type pour représenter les nombres rationnels : « rationnel.py » 8

5 Un type pour les rationnels : quelques exemples 95.1 Convergence d’une série . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95.2 Algorithme de Babylone (méthode de Héron d’Alexandrie) . . . . . . . . . . . . . . . . . . . . . . 11

6 Les listes en Python 126.1 Le type « list » de Python3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126.2 Fractions continues : le retour ! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

7 La programmation fonctionnelle 147.1 Fonctions pures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147.2 Curryfication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147.3 Fonction comme argument d’une autre fonction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

8 La programmation récursive 178.1 Retour sur les boucles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178.2 Spirale « carrée » . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188.3 Pentagones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

A Le module « outils.py » 20

B Le module « rationnel.py » 24

C Fractions continues : le calcul des réduites 26

1

1 L’ordinateur : un super-calculateur !

$ python3Python 3.2.3 (default , Feb 20 2013, 14:44:27)[GCC 4.7.2] on linux2Type "help", "copyright", "credits" or "license" for more information.>>> print (2**200)1606938044258990275541962092341162602522202993782792835301376>>>$

2

2 Un jeu d’enfants... pour voir2.1 La distributivité avec Python

Programme 1 – distributivite.py1 #!/usr/bin/env python32 # -*- coding: utf -8 -*-34 a = 1.15 b = 5.36 k = 2.278 p r i n t ( k*(a + b) )9 p r i n t ( k*a + k*b )

10 p r i n t ( (k*(a + b)) - (k*a + k*b) )

$ ./ distributivite.py14.08000000000000214.081.7763568394002505e-15$

3

2.2 La distributivité avec C

Programme 2 – distributivite.c1 #i n c l u d e <stdio.h>23 i n t main( i n t argc , c h a r *argv []) {4 doub l e a = 1.1;5 doub l e b = 5.3;6 doub l e k = 2.2;78 printf("%f\n", k*(a + b) );9 printf("%f\n", k*a + k*b );

10 printf("%f\n", (k*(a + b)) - (k*a + k*b) );11 r e t u r n 0;12 }

Le langage C exige une étape de compilation :

$ gcc distributivite.c$

$ ./a.out14.08000014.0800000.000000$

4

2.3 La distributivité avec Objective Caml

Programme 3 – distributivite.ml1 #!/usr/bin/env ocaml23 l e t calcul =4 l e t a = 1.1 i n5 l e t b = 5.3 i n6 l e t k = 2.2 i n7 print_float ( k *. (a +. b) );8 print_string "\n";9

10 print_float ( k *. a +. k *. b );11 print_string "\n";1213 print_float ( (k *. (a +. b)) -. (k *. a +. k *. b) );14 print_string "\n"15 ;;1617 calcul ;;

$ ./ distributivite.ml14.0814.081.7763568394e-15$

5

2.4 La distributivité avec Python : le retour !

Programme 4 – distributivite2.py1 #!/usr/bin/env python32 # -*- coding: utf -8 -*-34 f rom decimal impo r t *56 a = Decimal("1.1")7 b = Decimal("5.3")8 k = Decimal("2.2")9

10 p r i n t ( k*(a + b) )1112 p r i n t ( k*a + k*b )1314 p r i n t ( (k*(a + b)) - (k*a + k*b) )

$ ./ distributivite2.py14.0814.080.00$

6

3 Nombres décimaux et représentation binaireUn nombre décimal x en système décimal :

x = ap ap−1 . . . a2 a1 a0 ,a−1 a−2 a−3 . . . a−q 10

C’est-à-dire :

x =

(p∑

i=0

ai × 10i

)+

(q∑

i=0

a−i × 10−i

)

En système binaire :

x =

p′∑i=0

bi × 2i

+

q′∑i=0

b−i × 2−i

Le nombre « 1,1 » ne s’écrit pas bien en système binaire 1 !

1,110

= 1,000110011 . . .2

Le module « outils.py » présenté plus loin permet quelques conversions :

$ python3>>> from outils import *>>> approx (11, 10, 16, 10)’1 ,1000000000000000 ’>>> approx (11, 10, 16, 2)’1 ,0001100110011001 ’>>> approx (11, 10, 16, 3)’1 ,0022002200220022 ’>>>$

1. Le module « rationnel.py » présenté plus loin offre des outils pour la conversion entre bases de numération.

7

4 Un type pour représenter les nombres rationnels : « rationnel.py »Le programme ci-dessous exploite deux modules « rationnel.py » et « outils.py », dont le code source

complet est donné en annexe.

Programme 5 – calculsQ.py1 #!/usr/bin/env python32 # -*- coding: utf -8 -*-34 f rom rationnel impo r t *56 a = rationnel (1, 2)7 p r i n t (a)89 b = rationnel(-2, -6)

10 p r i n t (b)1112 c = a / rationnel (3)13 p r i n t (c)1415 p r i n t (a + b + c)1617 t = a * rationnel(-1, 7)18 p r i n t (t)1920 u = (t / b) ** 521 p r i n t (u)22 p r i n t (u.approximation ())23 p r i n t (u.approximation (30))24 p r i n t (u.fraction_continue ())

$ ./ calculsQ.py(1) /(2)(1) /(3)(1) /(6)(1)(-243) /(537824)-0 ,0004518206699589-0 ,000451820669958945677396322960[-1, 1, 2212, 3, 1, 2, 1, 4, 1, 2]$

8

5 Un type pour les rationnels : quelques exemples5.1 Convergence d’une série

Python permet de réaliser aisément la figure suivante, un peu à la manière du langage LOGO. Elle illustre

graphiquement la convergence de la série+∞∑i=1

(14

)i, à l’aide du module natif « turtle » de Python :

Programme 6 – dessin.py1 #!/usr/bin/env python32 # -*- coding: utf -8 -*-34 f rom turtle impo r t *56 d e f triangle(cote , code_couleur):7 i f code_couleur == 0: color("green")8 i f code_couleur == 1: color("white")9 i f code_couleur == 2: color("maroon")

10 begin_fill ()11 f o r i i n range (3):12 forward(cote)13 left (120)14 end_fill ()15 color("black")16 f o r i i n range (3):17 forward(cote)18 left (120)1920 d e f figure(n, cote):21 i f n > 0:22 triangle(cote , 0)23 triangle(cote/2, 1)24 forward(cote /2)25 triangle(cote/2, 2)26 backward(cote /2)27 left (60)28 forward(cote /2)29 right (60)30 figure(n - 1, cote /2)3132 figure(6, 512)

En Python, l’indentation du code-source est fondamentale : la profondeur détermine le début et la find’un bloc d’instructions.

9

On peut aussi mener la recherche naïve de la limite de la série, avec le programme suivant :

Programme 7 – serie.py1 #!/usr/bin/env python32 # -*- coding: utf -8 -*-34 f rom rationnel impo r t *56 #7 # quelques "constantes"8 #9 ZERO = rationnel ()

10 UN_QUART = rationnel (1, 4)1112 d e f somme_part(n):13 i f n > 0:14 r e t u r n UN_QUART ** n + somme_part(n-1)15 e l s e :16 r e t u r n ZERO1718 sigma = somme_part (5)19 p r i n t (sigma)20 p r i n t (sigma.approximation ())2122 sigma = somme_part (6)23 p r i n t (sigma)24 p r i n t (sigma.approximation ())

$ ./ serie.py(341) /(1024)0 ,3330078125000000(1365) /(4096)0 ,3332519531250000$

10

5.2 Algorithme de Babylone (méthode de Héron d’Alexandrie)

Programme 8 – babylone.py1 #!/usr/bin/env python32 # -*- coding: utf -8 -*-34 f rom rationnel impo r t *56 #7 # quelques "constantes"8 #9 UN = rationnel (1)

10 DEUX = rationnel (2)1112 d e f Babylone(a, x, n):13 i f n > 0:14 t = Babylone(a, x, n-1)15 r e t u r n (t + (a/t))/DEUX16 e l s e :17 r e t u r n UN1819 a = rationnel (5)20 r = Babylone(a, UN , 8)2122 p r i n t ("Une␣approximation␣de␣la␣racine␣carree␣de", a, "est:")23 p r i n t (r)24 p r i n t (r.approximation (40))25 p r i n t (r.fraction_continue ())

$ ./ babylone.pyUne approximation de la racine carree de (5) est:(316837008400094222150776738483768236006420971486980607)

/(141693817714056513234709965875411919657707794958199867)2 ,2360679774997896964091736687312762354406[2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,

4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,4, 4, 4, 4, 4, 4, 3]

$

On peut démontrer rapidement à la main la périodicité du développement en fraction continue de√5 :

√5 = 2 +

1

4 +1

4 +1

...

Soit en notation abrégée de la période :√5 =

[2 , 4

]

11

6 Les listes en Python6.1 Le type « list » de Python3

$ python3Python 3.2.3 (default , Feb 20 2013, 14:44:27)[GCC 4.7.2] on linux2Type "help", "copyright", "credits" or "license" for more information.>>> a = ["chevre", "loup", "chou"]>>> a[’chevre ’, ’loup ’, ’chou ’]>>> del a[1]>>> a[’chevre ’, ’chou ’]>>> len(a)2>>> a.append("loup")>>> a[’chevre ’, ’chou ’, ’loup ’]>>> x = a.pop()>>> x’loup ’>>> a[’chevre ’, ’chou ’]>>> a.insert(0, x)>>> a[’loup ’, ’chevre ’, ’chou ’]>>> a.reverse ()>>> a[’chou ’, ’chevre ’, ’loup ’]>>>$

$ python3Python 3.2.3 (default , Feb 20 2013, 14:44:27)[GCC 4.7.2] on linux2Type "help", "copyright", "credits" or "license" for more information.>>> a = [ n*(n+1)/2 for n in range (10) ]>>> a[0.0, 1.0, 3.0, 6.0, 10.0, 15.0, 21.0, 28.0, 36.0, 45.0]>>> a = [ n*(n+1) //2 for n in range (10) ]>>> a[0, 1, 3, 6, 10, 15, 21, 28, 36, 45]>>> b = range(3, 20, 4)>>> print(list(b))[3, 7, 11, 15, 19]>>>$

12

6.2 Fractions continues : le retour !

Programme 9 – reduite.py1 #!/usr/bin/env python32 # -*- coding: utf -8 -*-34 f rom rationnel impo r t *56 d e f reduite(quotients , r):7 i f len(quotients) > 0:8 r e t u r n rationnel(quotients [0]) + rationnel (1) / reduite(quotients [1:], r)9 e l s e :

10 r e t u r n r1112 d e f calcul_reduite(quotients):13 r e t u r n reduite(quotients , rationnel ())1415 d e f tests_unitaires ():16 r = rationnel (4291 , 1329)17 p r i n t (r)18 a = r.fraction_continue ()19 p r i n t (a)20 p r i n t (calcul_reduite(a))2122 i f __name__ == "__main__":23 tests_unitaires ()

$ ./ reduite.py(4291) /(1329)[3, 4, 2, 1, 2, 4, 2, 1, 2](4291) /(1329)$

On consultera en annexe une méthode de calcul faisant appel aux suites définies par récurrence. La méthodevalable pour les nombres rationnels s’étend aux irrationnels quadratiques.

Le module rationnel.py offre déjà dans forme minimale actuelle un bon champ d’investigation en classe,avec une construction déjà accessible aux élèves.

13

7 La programmation fonctionnelleProgrammation fonctionnelle

On exprime la solution d’un problème en termes d’appels de fonctions. La notion de récursivité (et partant,de fonction) est prépondérante dans ce modèle de programmation.

Programmation impérativeOn procède par modifications successives des états de la machine. Dans ce style de programmation,l’assignation de valeur (affectation) joue un rôle central. L’aspect séquentiel est très important à considérer.

Une précision terminologique, importante pour la classeOn distingue deux sens au mot « fonction », en Mathématiques et en programmation :– en Mathématiques : (...)– en programmation : une fonction est un sous-programme ou routine (c’est-à-dire un programme dans le

programme) que le programme (ou toute routine du programme) pourra invoquer à loisir.Une fonction peut comporter des paramètres, et modifier (selon les règles du langage) son environnementexterne.Un appel de fonction rend un résultat ; une procédure est une fonction ne délivrant aucun résultat, plusexactement le résultat « vide ».

En programmation fonctionnelle, les fonctions sont des types de données, au même titre que les entiers,flottants, chaînes de caractères, types composés ou objets... Une fonction peut par exemple servir de paramètreà une autre fonction.

7.1 Fonctions puresEn programmation, une fonction est dite « fonction pure » lorsque :– elle a pour seul effet de rendre un résultat, i.-e. elle ne modifie pas son environnement (son contexte

d’exécution) ;– entre différentes invocations, la fonction rend le même résultat pour les mêmes arguments.

7.2 Curryfication

Programme 10 – curry.py1 #!/usr/bin/env python32 # -*- coding: utf -8 -*-34 d e f ajoute(x):5 r e t u r n lambda y: x + y67 p r i n t ( ajoute (3) (4) )

Programme 11 – curry.ml1 #!/usr/bin/env ocaml23 let ajoute x =4 function y -> x + y;;56 print_int (( ajoute 3) 4);;7 print_string "\n";;

14

7.3 Fonction comme argument d’une autre fonction

Programme 12 – trinome.py1 #!/usr/bin/env python32 # -*- coding: utf -8 -*-34 f rom rationnel impo r t *56 #7 # p(x) = 3*x^2 + 3*x + 2/38 #9 d e f p(x):

10 a = rationnel (3)11 b = rationnel (2, 3)12 r e t u r n a * x ** 2 + a * x + b1314 PI = rationnel (22, 7)1516 u = p(PI)17 p r i n t (u)18 p r i n t (u.approximation (20))1920 d e f image(f, x):21 r e t u r n f(x)2223 v = image(p, PI)24 p r i n t (v)25 p r i n t (v.approximation ())

15

Deux modèles de calcul de30∑i=1

i :

Programme 13 – somme1.py1 #!/usr/bin/env python32 # -*- coding: utf -8 -*-34 somme = 056 f o r i i n range (30 + 1):7 somme = somme + i89 p r i n t (somme)

Programme 14 – somme2.py1 #!/usr/bin/env python32 # -*- coding: utf -8 -*-34 d e f somme(n):5 i f n > 0:6 r e t u r n n + somme(n-1)7 e l s e :8 r e t u r n 09

10 p r i n t (somme (30))

Note : le programme somme2.py peut être amélioré par une version « récursive terminale ».

16

8 La programmation récursive8.1 Retour sur les boucles

Programme 15 – boucle1.py1 #!/usr/bin/env python32 # -*- coding: utf -8 -*-34 d e f boucle(n):5 i f n > 0:6 p r i n t (n)7 boucle(n - 1)89 boucle (10)

Programme 16 – boucle2.py1 #!/usr/bin/env python32 # -*- coding: utf -8 -*-34 d e f boucle(n):5 i f n > 0:6 boucle(n - 1)7 p r i n t (n)89 boucle (10)

Programme 17 – boucle3.py1 #!/usr/bin/env python32 # -*- coding: utf -8 -*-34 d e f boucle(a, n):5 i f n >= a:6 boucle(a, n - 1)7 p r i n t (n)89 boucle(3, 15)

À titre d’exercice, on pourra s’entraîner à concevoir récursivement le dessin suivant :

17

8.2 Spirale « carrée »On fixe un entier naturel p strictement positif et on recherche la plus longue spirale à côtés entiers, de

longueur inférieure à p, que l’on peut construire sur le modèle ci-dessous :

(on conviendra d’un nombre donné de pixels pour une unité de longueur)

Le programme de dessin de la spirale et la détermination de la longueur de son plus côté donnent lieu àdeux programmes qui illustrent parfaitement la récursivité.

18

8.3 PentagonesLe programme suivant est un exemple de programmation impérative. La traduction en programmation récur-

sive constitue un excellent exercice.

Programme 18 – penta1.py1 #!/usr/bin/env python32 # -*- coding: utf -8 -*-34 f rom math impo r t *5 f rom turtle impo r t *67 d e f pentagone(cote):8 f o r n i n range (5):9 forward(cote)

10 left (72)1112 d e f spirale(nombre_triangles , cote):13 coeff = 0.114 a = cote15 d = coeff * a16 f o r i i n range(nombre_triangles):17 pentagone(a)18 d = coeff * a19 forward(d)20 a_prime = sqrt((a-d)**2 + d**2 -2*(a-d)*d*(1-sqrt (5))/4)21 angle = (180/ pi) * acos( (a_prime **2 + a**2 - 2*a*d)/(2* a_prime *(a-d)) )22 left(angle)23 a = a_prime2425 d e f dessin ():26 up()27 goto (-190,-210)28 down()29 spirale (50, 370)30 up()3132 i f __name__ == "__main__":33 speed("fastest")34 dessin ()3536 p r i n t "Appuyez␣sur␣la␣touche␣de␣VALIDATION␣pour␣terminer."37 touche = str(raw_input ())

19

A Le module « outils.py »

Programme 19 – outils.py1 #!/usr/bin/env python32 # -*- coding: utf -8 -*-34 impo r t sys5 sys.setrecursionlimit (10000)67 #8 # (a, b) dans N x N*9 #

10 d e f reste(a, b):11 i f a < b:12 r e t u r n a13 e l s e :14 r e t u r n reste(a - b, b)1516 #17 # (a, b) dans N x N*18 #19 d e f quotient_entier(a, b):20 i f a < b:21 r e t u r n 022 e l s e :23 r e t u r n 1 + quotient_entier(a - b, b)2425 #26 # (a, b) dans N x N27 #28 d e f pgcd(a, b):29 i f b == 0:30 r e t u r n a31 e l s e :32 r e t u r n pgcd(b, reste(a, b))3334 #35 # (a, b) dans N x N*36 #37 d e f fraction_cont_pos(q, a, b):38 q.append(quotient_entier(a, b))39 i f reste(a, b) > 0:40 r e t u r n fraction_cont_pos(q, b, reste(a, b))41 e l s e :42 r e t u r n q4344 #45 # (a, b) dans Z x N*46 #47 d e f fraction_cont_b_pos(a, b):48 q = []49 i f a < 0:50 q.append(-quotient_entier(-a + b, b))51 e l s e :52 q.append(quotient_entier(a, b))53 r e t u r n q + fraction_cont_pos ([], a - b * q[0], b)[1:]5455 #

20

56 # (a, b) dans Z x Z*57 #58 d e f fraction_cont(a, b):59 i f b < 0:60 r e t u r n fraction_cont_b_pos(-a, -b)61 e l s e :62 r e t u r n fraction_cont_b_pos(a, b)6364 d e f partie_ent(chiffres , x, base):65 i f x > 0:66 partie_ent(chiffres , quotient_entier(x, base), base)67 chiffres.append(str(reste(x, base)))6869 d e f partie_frac(chiffres , n, a, b, base):70 i f n > 0:71 chiffres.append(str(quotient_entier(a * base , b)))72 partie_frac(chiffres , n - 1, reste(a * base , b), b, base)7374 d e f approx_pos(chiffres , p, q, nombre_chiffres , base):75 t = quotient_entier(p, q)76 i f t == 0:77 chiffres.append("0")78 e l s e :79 partie_ent(chiffres , t, base)80 i f reste(p, q) > 0:81 chiffres.append(",")82 partie_frac(chiffres , nombre_chiffres , reste(p, q), q, base)83 r e t u r n chiffres8485 d e f approx_q_pos(p, q, nombre_chiffres , base):86 chiffres = []87 i f p < 0:88 chiffres.append("-")89 approx_pos(chiffres , -p, q, nombre_chiffres , base)90 e l s e :91 approx_pos(chiffres , p, q, nombre_chiffres , base)92 r e t u r n "".join(chiffres)9394 d e f approx(p, q, nombre_chiffres , base):95 i f q < 0:96 r e t u r n approx_q_pos(-p, -q, nombre_chiffres , base)97 e l s e :98 r e t u r n approx_q_pos(p, q, nombre_chiffres , base)99

100 d e f approximation(p, q, nombre_chiffres =16, base =10):101 #102 # on impose la base <= 10 (pour les digits)103 #104 i f base > 10:105 base = 10106 r e t u r n approx(p, q, nombre_chiffres , base)107108 #109 # tests unitaires110 #111 d e f tests_unitaires ():112 #113 # quelques "constantes" utiles pour les tests114 #

21

115 BASE_DEUX = 2116 BASE_DIX = 10117 CHIFFRES_DROITE_VIRGULE = 16118119 #120 # approximation du rationnel -4565/21121 #122 p r i n t (approx (-4565, 21, CHIFFRES_DROITE_VIRGULE , BASE_DIX))123124 #125 # approximation du rationnel ( -4565) /(-21)126 #127 p r i n t (approx (4565, -21, CHIFFRES_DROITE_VIRGULE , BASE_DIX))128129 #130 # expression du rationnel 4565/21 comme fraction continue131 #132 p r i n t (fraction_cont (4565 , 21))133134 #135 # expression du rationnel -4565/21 comme fraction continue136 #137 p r i n t (fraction_cont (-4565, 21))138139 #140 # expression du rationnel 2/3 comme fraction continue141 #142 p r i n t (fraction_cont (2, 3))143144 #145 # expression du rationnel -2/3 comme fraction continue146 #147 p r i n t (fraction_cont (2, -3))148149 #150 # approximation du rationnel 11/10151 #152 p r i n t (approx (11, 10, CHIFFRES_DROITE_VIRGULE , BASE_DIX))153154 #155 # approximation du rationnel 11/10 en base 2156 #157 p r i n t (approx (11, 10, CHIFFRES_DROITE_VIRGULE , BASE_DEUX))158159 p r i n t (approx (100, 20, CHIFFRES_DROITE_VIRGULE , BASE_DIX))160 p r i n t (approx (21, 4565, CHIFFRES_DROITE_VIRGULE , BASE_DIX))161 p r i n t (approximation (179, 260, 25))162163 i f __name__ == "__main__":164 tests_unitaires ()

Note : pour des raisons purement techniques, et éviter d’alourdir le code source sans offrir le moindre intérêtmathématique, le choix à été fait de limiter les conversions aux bases inférieures ou égales à 10.

22

Après l’étude sur le calcul du reste, du quotient... on peut s’affranchir des fonctions reste et quotient_entierdéfinies « à la main », en utilisant celles fournies par le langage. Par exemple :

Programme 20 – outils2.py1 #!/usr/bin/env python32 # -*- coding: utf -8 -*-34 impo r t sys5 sys.setrecursionlimit (10000)67 #8 # (a, b) dans N x N*9 #

10 d e f reste(a, b):11 r e t u r n (a % b)1213 #14 # (a, b) dans N x N*15 #16 d e f quotient_entier(a, b):17 r e t u r n (a // b)1819 #20 # (a, b) dans N x N21 #22 d e f pgcd(a, b):23 i f a == 0 and b == 0:24 r e t u r n 125 e l s e :26 w h i l e b > 0:27 r = reste(a, b); a = b; b = r28 r e t u r n a2930 #31 # ... la suite du fichier est identique.32 #

La fonction pgcd a également écrite de façon impérative, avec en plus un test initial, de sorte que :

PGCD (0, 0) = 1 .

23

B Le module « rationnel.py »

Programme 21 – rationnel.py1 #!/usr/bin/env python32 # -*- coding: utf -8 -*-34 f rom outils impo r t *56 c l a s s rationnel(object):78 d e f __init__(self , num =0, denom =1):9 i f denom == 0:

10 #11 # signaler une erreur ici12 #13 num = 014 denom = 11516 i f denom < 0:17 p = -num18 q = -denom19 e l s e :20 p = num21 q = denom2223 d = pgcd(abs(p), q)2425 self.__num = p // d26 self.__denom = q // d2728 d e f __str__(self):29 i f self.__denom == 1:30 r e t u r n ("("+str(self.__num)+")")3132 r e t u r n ("("+str(self.__num)+")/("+str(self.__denom)+")")3334 d e f __add__(self , autre):35 num = self.__num * autre.__denom + self.__denom * autre.__num36 denom = self.__denom * autre.__denom37 r e t u r n rationnel(num , denom)3839 d e f __neg__(self):40 r e t u r n rationnel(-(self.__num), self.__denom)4142 d e f __sub__(self , autre):43 num = self.__num * autre.__denom - self.__denom * autre.__num44 denom = self.__denom * autre.__denom45 r e t u r n rationnel(num , denom)4647 d e f __mul__(self , autre):48 num = self.__num * autre.__num49 denom = self.__denom * autre.__denom50 r e t u r n rationnel(num , denom)5152 d e f __truediv__(self , autre):53 i f autre.__num == 0:54 #55 # signaler une erreur ici

24

56 #57 r e t u r n rationnel ()58 num = self.__num * autre.__denom59 denom = self.__denom * autre.__num60 r e t u r n rationnel(num , denom)6162 d e f __pow__(self , exposant):63 i f self.__num == 0 and exposant == 0:64 #65 # signaler une erreur ici66 #67 r e t u r n rationnel ()6869 i f exposant < 0:70 r e t u r n rationnel(self.__denom ** (-exposant), self.__num ** (-exposant))71 e l s e :72 r e t u r n rationnel(self.__num ** exposant , self.__denom ** exposant)7374 d e f approximation(self , chiffres_apres_virgule =16):75 r e t u r n approximation(self.__num , self.__denom , chiffres_apres_virgule)7677 d e f fraction_continue(self):78 r e t u r n fraction_cont(self.__num , self.__denom)7980 d e f tests_unitaires ():81 a = rationnel (28, -561)82 p r i n t (a)83 p r i n t (a.approximation ())84 p r i n t (a.fraction_continue ())8586 b = rationnel (3)87 p r i n t (b)8889 t = a + b90 p r i n t (t)9192 t = a - b93 p r i n t (t)9495 t = a * b96 p r i n t (t)9798 t = a / b99 p r i n t (t)

100 p r i n t (t.approximation (100))101102 t = a ** 3103 p r i n t (t)104 p r i n t (t.approximation (100))105106 i f __name__ == "__main__":107 tests_unitaires ()

25

C Fractions continues : le calcul des réduitesL’intérêt historique des fractions continues réside dans l’approximation des nombres réels par des rationnels.

On suppose établie une écriture d’un nombre réel x sous la forme des quotients partiels (entiers) (ai)i∈N :

x = [a0 , a1 , a2 , a3 , . . . , an , . . . ]

Cette écriture est finie quand x est rationnel, périodique si x est un nombre irrationnel quadratique, infiniepour les nombres transcendants.

On peut procéder au calcul des réduites successives par l’« algorithme des fractions continues » ci-dessous.

On pose :

∀n ∈ N,

{pn+1 = anpn + pn−1

qn+1 = anqn + qn−1

avec les conventions : p−1 = 0 , p0 = 1 et q−1 = 1 , q0 = 0 .

La suite des réduites successives(pnqn

)n∈N

converge vers x, avec : limn→+∞

qn = +∞.

D’un point de vue purement mathématique, on peut agrémenter les deux suites (pn)n∈N et (pn)n∈N d’unetroisième suite des quotients incomplets (an)n∈N, définie par :

∀n ∈ N, an =

⌊−qn−1x− pn−1

qnx− pn

avec la réserve qnx− pn 6= 0 (ce qui est le cas lorsque x est irrationnel).

La suite (an)n∈N nécessite dans le calcul de chaque terme l’emploi du réel x avant d’évaluer la partieentière du quotient, ce qui pose la question du choix convenable d’une valeur approchée de x pour le calculeffectif restreint au type « rationnel ».

Exemple de calcul des premiers quotients incomplets pour√11 :

i −1 0 1 2 3 4 . . .

pi 0 1 3 10

qi 1 0 1 3

ai • 3 3 6

26

top related