8.3. Arithmétique¶
8.3.1. Décomposition d’un entier dans une base¶
L’écriture d’un entier
où les
On peut obtenir la liste
donc
In [1]: def decomp(n, b):
...: l = []
...: while n != 0:
...: l.append(n % b)
...: n //= b
...: return l
...:
In [2]: decomp(24189, 10 )
Out[2]: [9, 8, 1, 4, 2]
In [3]: n, b = 3678, 7
In [4]: l = decomp(n, b)
In [5]: l
Out[5]: [3, 0, 5, 3, 1]
# On vérifie que la liste convient effectivement
In [6]: sum(a * b ** i for i, a in enumerate(l))
Out[6]: 3678
8.3.2. Calcul de PGCD¶
On peut implémenter l’algorithme d’Euclide en Python.
In [7]: def pgcd(a, b):
...: while b != 0:
...: a, b = b, a % b
...: return abs(a) # Le pgcd doit être positif
...:
In [8]: pgcd(30, 12)
Out[8]: 6
In [9]: pgcd(30, -12)
Out[9]: 6
De même, on peut implémenter l’algorithme d’Euclide étendu qui, en plus du pgcd, donne des coefficients d’une relation de Bézout, c’est-à-dire des entiers
In [10]: def bezout(a, b):
....: s, t, u, v = 1, 0, 0, 1
....: while b != 0:
....: q = a // b
....: a, s, t, b, u, v = b, u, v, a - q * b, s - q * u, t - q * v
....: return (a, s, t) if a > 0 else (-a, -s, -t) # Le pgcd doit être positif
....:
In [11]: bezout(30, 12)
Out[11]: (6, 1, -2)
In [12]: bezout(30, -12)
Out[12]: (6, -1, -3)
La preuve de l’algorithme est donnée en annexe.
8.3.3. Exponentiation rapide¶
Il s’agit ici de calculer efficacement une puissance entière d’un objet mathématique (nombre ou matrice par exemple). Un algorithme naïf serait le suivant.
In [13]: def exponentiation(x, n):
....: a = 1
....: for _ in range(n):
....: a *= x
....: return a
....:
In [14]: exponentiation(3, 5)
Out[14]: 243
Il est clair que cet algorithme nécessite
On peut proposer un léger raffinement pour éviter une multiplication.
In [15]: def exponentiation2(x, n):
....: if n == 0:
....: return 1
....: a = x
....: for _ in range(n-1):
....: a *= x
....: return a
....:
In [16]: exponentiation2(3, 5)
Out[16]: 243
Mais on peut être beaucoup plus efficace. On remarque que toute puissance
Il suffit alors de calculer successivement les
3 multiplications pour calculer successivement
, et ;2 multiplications pour effectuer le produit de
, et .
On effectue en tout 5 multiplications au lieu de 12.
Pour obtenir la décomposition de
In [17]: def exponentiation_rapide(x, n):
....: a = 1
....: p = x
....: while n > 0:
....: if n % 2 == 1:
....: a *= p
....: p *= p
....: n //= 2
....: return a
....:
In [18]: exponentiation_rapide(3, 5)
Out[18]: 243
On peut également proposer un raffinement pour gagner une multiplication. En effet, à la dernière itération, l’instruction p *= p
est inutile puisque cette dernière valeur de p
ne sera pas utilisée. De plus, à la dernière itération, n
vaut 1
qui est impair donc l’instruction a *= p
sera obligatoirement effectuée.
In [19]: def exponentiation_rapide2(x, n):
....: if n == 0:
....: return 1
....: a = 1
....: p = x
....: while n > 1:
....: if n % 2 == 1:
....: a *= p
....: p *= p
....: n //= 2
....: return a * p
....:
In [20]: exponentiation_rapide2(3, 5)
Out[20]: 243
8.3.4. Evaluation de polynômes¶
La méthode naïve pour évaluer un polynôme
Par exemple, pour évaluer
les puissances de
, à savoir et (2 multiplications) ;les produits
, et (3 multiplications) ;la somme de
, , et (3 additions).
Mais les calculs peuvent être menés plus astucieusement en remarquant que :
On calcule alors successivement :
(1 multiplication et 1 addition) ; (1 multiplication et 1 addition) ; (1 multiplication et 1 addition).
On a gagné deux multiplications par rapport à la méthode précédente et on comprend bien que le gain sera d’autant plus grand que le polynôme est de degré élevé.
L’algorithme décrit dans l’exemple précédent s’appelle la méthode de Hörner. Pour implémenter cet algorithme, on représente un polynôme par la liste de ses coefficients rangés par ordre décroissant de degré. Par exemple, la liste [1, 2, 3]
représente le polynôme
In [21]: def horner(poly, x):
....: s = 0
....: for c in poly:
....: s = s * x + c
....: return s
....:
# On évalue le polynôme X²+2X+3 en 4
In [22]: horner([1, 2, 3], 4)
Out[22]: 27
Si l’on préfère représenter un polynôme par la liste de ses coefficients par ordre de degré croissant, on peut toujours utiliser la fonction reversed
qui fait ce que son nom indique [1].
In [23]: def horner(poly, x):
....: s = 0
....: for c in reversed(poly):
....: s = s * x + c
....: return s
....:
# On évalue le polynôme 1+2X+3X² en 4
In [24]: horner([1, 2, 3], 4)
Out[24]: 57