TP 7 : ´ecriture en base deux et exponentiation rapide
1 Ecriture en base deux
On va ´ecrire un algorithme it´eratif (boucle while) permettant d’obtenir l’´ecriture en base deux
d’un nombre entier n.
Deux m´ethodes sont possibles.
(M1) Des poids forts vers les poids faibles : Mettons qu’on veuille savoir comment s’´ecrit
54 en base deux. On commence par se demander entre quelles puissances de deux il est : ici 32 et
64. On sait alors quel est le premier chiffre (en partant de la gauche, celui qu’on appelle le chiffre
de poids fort) de son ´ecriture en base deux : comme 32 =25, 54 =25+(54 32)=25+22. On fait
le mˆeme travail pour 22, etc.
(M2) Des poids faibles vers les poids forts : L’id´ee de d´epart est que si n=br2r+⋯+b12+b0
alors en particulier n=2B+b0o`u Best un entier et b0{0,1}. Donc b0est le reste de la division
euclidienne de npar 2. Donc on sait calculer b0, le dernier chiffre de l’´ecriture de nen base 2 (le
chiffre de poids le plus faible). On a bien sˆur b0=si nest pair et b0=si nest impair. Pour 54
ce chiffre fait donc .
On peut ensuite appliquer la mˆeme m´ethode au quotient Bde cette division euclidienne. A
partir de l’´ecriture de d´epart, B=br2r1+ ⋯b2.2+b1et ceci permet d’obtenir b1etc...
Illustration sur un exemple :
24 =2×12 +0b0=0,
12 =2×6+0b1=0,
6=2×3+0b2=0,
3=2×1+1b3=1,
1=2×0+1b4=1.
Question 1 : Impl´ementer un algorithme suivant la m´ethode (M2).
On notera base2PoidsFaibles la fonction correspondante, prenant un entier naturel nen
argument, et renvoyant la liste [br, br1,...,b0]de ses chiffres en base deux (dans cet ordre !).
Remarque : penser aux cas particuliers.
Question 2 : Ecrire une fonction puissance2inf qui pour chaque entier n1 renvoie le plus
grand entier rtel que 2rnet renvoie 0 si n=0.
Question 3 : En d´eduire l’´ecriture d’un algorithme suivant la m´ethode (M1) (plus compliqu´ee).
2 L’algorithme d’exponentiation rapide
Le but de cette algorithme est de calculer la puissance N-i`eme xNd’un nombre xqui peut ˆetre
un entier ou un flottant, avec un minimum d’op´erations.
L’inerˆet de cet algo. ne se limite pas aux entiers. Si on l’introduit ici, c’est qu’ensuite on
l’appliquera aussi dans les anneaux de congruences, o`u il est encore plus efficace, et qu’on
s’en servira pour des probl`emes d’arithm´etiques...
a) L’id´ee essentielle : Si N=a0+a12⋅ ⋅ ⋅ + an2n, ´ecriture en base deux, avec ai{0,1}alors :
xN=xa0(x2)a1...(x2n)an.
Ensuite deux points de vue possibles, cela d´epend si on connait d´ej`a l’´ecriture en base 2 de
Nou pas.
1
b) 1`ere m´ethode (des poids faibles vers les poids forts)
En lisant le d´eveloppement en base deux de droite `a gauche si N=(an...a0)[2]: c’est le
plus souvent comme cela que l’algorithme est pr´esent´e, car dans ce cas, on peut aussi obtenir
les chiffres successifs du d´eveloppement en base 2`a chaque ´etape par l’algorithme des poids
faibles d´ej`a vu plus haut : pas besoin d’avoir fait le calcul du d´ev. en base 2 avant !
Pour mettre en oeuvre l’algorithme on utilise trois variables qu’on va appeler res et aux
comme r´esultat et auxiliaire et la variable Nqui au d´epart contient comme valeur l’exposant
Net qui va permettre `a chaque ´etape de calculer le chiffre du d´eveloppement en base 2 de
N.
De mani`ere pas compl`etement formelle, `a l’´etape i:
On stocke dans aux la valeur de x2i, obtenue comme carr´e de x2i1obtenu `a l’´etape
pr´ec´edente.
En mˆeme temps, on divise `a chaque ´etape Npar 2 pour connaˆıtre le i-`eme chiffre aide
son ´ecriture en base 2. i.e. on it`ere N =N//2 . Le aiest le reste de la division euclidienne
de Npar 2.
Enfin toujours `a l’´etape i,si ai=1, on multiplie res par x2ic’est-`a-dire la valeur de
aux `a l’´etape i, sinon on ne change pas res.
Exercice `a faire : impl´ementer cette id´ee d’algorithme en Python.
Rappel l’algo. de d´ev. en base deux des poids faibles vers les poids forts illustr´e
sur un exple :
24 =2×12 +0a0=0,
12 =2×6+0a1=0,
6=2×3+0a2=0,
3=2×1+1a3=1,
1=2×0+1a4=1.
c) 2`eme m´ethode (des poids forts vers les poids faibles)
En lisant l’´ecriture en base 2de gauche `a droite : cette m´ethode ´evite l’utilisation d’une
variable auxiliaire, mais n´ecessite d’avoir calcul´e le d´eveloppement en base 2 de N: ce qui
n’est pas un gros probl`eme pratique en Python, mais jouerait sur les questions de coˆut.
L’id´ee astucieuse, qui est utile dans d’autres contextes (algorithme de H¨orner), est d’´ecrire :
xN=((...(xan)2xan1)2...)xa1)2xa0
Par exemple avec 24 qui s’´ecrit 11000 en base 2 : x24 =(((x)2.x)2)2)2).
On lit donc l’´ecriture en base 2de Nde gauche `a droite, on part de res:= 1 et `a chaque
´etape s’il y a un 1dans le d´eveloppement de Nen base 2on remplace res par (res*res)*x,
sinon on prend juste le carr´e i.e. on remplace res par (res*res).
Exercice `a faire : impl´ementer cette id´ee d’algorithme en Python
d) Montrer que si Ns’´ecrit avec n+1 chiffres en base 2, alors cet algorithme permet de calculer
xNavec au plus 2nmultiplications.
e) Comparer la vitesse de vos fonctions avec celle de la fonction pow(x,N) de Python qui
utilise ce mˆeme algorithme d’exponentiation rapide.
2
Solutions pour le TP 7 : ´ecriture en base deux
1 Ecriture en base deux
Question 1 :
Bien comprendre comment on fabrique la boucle : `a chaque ´etape, on prend le reste de la
division euclidienne de npar 2, qu’on doit stocker dans une liste, et on remplace npar n//2.
Une fois qu’on a compris cela, on a compris la boucle en r´egime de croisi`ere , il ne reste
plus qu’`a initialiser et mettre la condition d’arrˆet.
## Ecriture Base 2 en commen¸cant par les poids faibles
def base2_poids_faible(n):
liste=[]
if n==0:
liste=[0] # Cas `a mettre `a part car n’entre pas dans la boucle qui suit
else :
while (n>0):
a=n%2
liste=[a]+liste # du bon c^ot´e...
n=n//2 # quotient de la div. eucl.
return liste
Question 2 :
Ce que j’ai vu en g´en´eral ressemblait `a :
def puissance2inf1(n):
if n==0:
return 0
else:
i=0
while 2**i <n:
i+=1
if 2**i==n:
return i
else :
return i-1
Ce code illustre bien la diff´erence entre ce qui se passe si notre nombre est pile une puissance
de 2 ou pas. Mais on peut ´eviter les deux cas `a la fin, avec un test 2**i<=n plus malin (beaucoup
vu aussi) :
def puissance2inf2(n):
if n==0:
return 0
else:
i=0
while 2**i <=n:
i+=1
return i-1 # rattrapage final...
Informatiquement, les deux codes pr´ec´edents ont un gros d´efaut : le calcul de 2**i `a chaque
´etape. Il est pr´ef´erable de cr´eer un accumulateur qui est multipli´e par 2 `a chaque ´etape. C’est
ce qu’on fait dans la v.3 ci-dessous.
3
def puissance2inf3(n):
if n==0:
return 0
else:
i=0
acc=1
while acc <=n:
i=i+1
acc=2*acc
return i-1
On peut aussi penser le probl`eme en sens inverse.
def puissance2inf4(n):
r=0
while n>1:
r = r+1
n = n//2
return r
Question : Expliquer pourquoi ce quatri`eme script donne aussi le bon r´esultat .
4
Question 3 :
def poids_fort(n):
#cr´eation d’une liste auxiliaire avec la bonne longueur
if n==0:
liste=[0]
else:
r=puissance2inf(n)
liste=[1]+[0]*r
l=r+1 # la longueur de la liste
# on a cr´e une liste du bon format, on va continuer `a la remplir
n=n-2**r #
while n!=0:
r=puissance2inf(n)
liste[l-1-r]=1
n=n-2**r
return liste
Remarque : L’algo. des poids forts, au d´epart plus intuitif pour un humain est : plus difficile
`a programmer, et surtout plus lent (facteur 5 pour un test avec time). On peut bien sˆur essayer de
l’optimiser un peu. Par exemple le n=n-2**r est tr`es mauvais : on recalcule 2**r. Pour ´eviter cela,
on pourrait modifier puissance2inf pour lui faire renvoyer non seulement l’exposant r, mais la
valeur de 2r, puisque il est facile de la faire calculer `a moindre coˆut par cette fonction : inutile de
la calculer deux fois. Mais mˆeme ainsi l’algo. reste plus lent. La division euclidienne est une arme
tr`es efficace !
5
1 / 5 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !