11 avril 2020 — Introduction, Python
Les entiers naturels , c’est l’ensemble des nombres suivants :
Ils portent plutôt bien leur nom, car ils sont effectivement très intuitifs et tout le monde comprend leur sens : ce sont ceux que l’on utilise pour compter des objets.
On dit qu’un entier est divisible par un entier s’il existe un entier tel que .
On peut visualiser ce concept comme la possibilité de regrouper par lots. Par exemple, est divisible par 2 et par 3 :
Parmi ces nombres, certains ont une propriété particulière.
Un nombre premier est un nombre qui ne se casse pas quand on le laisse tomber par terre. (P. Erdős)
Un entier est dit premier s’il n’admet que deux diviseurs : et lui-même ( n’est pas considéré premier).
Par exemple, les nombres sont premiers : pour vous en convaincre, essayez de ranger cinq 🍋 en lots de , ou .
Si vous prenez un nombre d’objets, et essayez de les répartir entre personnes, il n’est pas sûr que vous puissiez y arriver. Par exemple, si et , vous allez en donner un au premier, le suivant au second, etc. et il va vous en rester deux dans les mains après avoir partagé les six premiers, car .
La division euclidienne généralise ce procédé.
et étant des entiers naturels, avec , il existe des entiers naturels (quotient) et (reste) uniques vérifiant :
et
Je laisse le lecteur vérifier que si une telle décomposition existe, alors elle est unique. Pour montrer son existence, une approche est de décrire un algorithme pour obtenir et .
💻 L’algorithme Python ci-dessous permet d’obtenir cette décomposition (note: cet algorithme n’est pas optimal).
def euclidean_division(a, b):q, r = 0, awhile r >= b:r -= bq += 1return (q, r)>>> euclidean_division(8, 3)(2, 2) # 8 = 3 * 2 + 2>>> euclidean_division(2020, 51)(39, 31) # 2020 = 51 * 39 + 31
On vérfie que l’égalité est un invariant de boucle car à chaque itération décroit de et augmente de .
Ceci permet de prouver que cet algorithme termine après un nombre fini d’itérations et donne un résultat vérifiant les conditions requises. Mathématiquement, c’est une preuve de l’existence pour notre théorème de division euclidienne.
euclidean_division(42, 0)
?q
et r
?Comme vous le savez, nous utilisons aussi des nombres négatifs.
💡 D’un point de vue axiomatique, ces nombres peuvent être définis comme des différences : est le nombre qui permet de passer de à , ou de façon équivalente de à (en savoir plus).
On note l’ensemble des nombres entiers relatifs (positifs, négatifs ou nuls) :
Les entiers relatifs contiennent les entiers naturels, ce qu’on note : .
La division euclidienne existe toujours dans , mais le quotient peut être négatif.
💻 En exercice, vous pouvez essayer d’adapter la fonction euclidean_division
précédente
pour qu’elle fonctionne avec .
Nous avons l’habitude d’écrire les nombres en base 10, avec dix chiffres différents .
Ce choix est pratique, il permet de compter avec ses mains.
Pour des raisons qui relèvent principalement de l’électronique, le choix de la base (binaire) s’est imposé pour représenter les nombres en informatique (en mémoire, dans les canaux d’échange, etc.).
Ce choix a des conséquences importantes sur lesquelles nous reviendrons.
Le programme ci-dessous permet d’afficher la liste des chiffres d’un entier , en base décimale, en commençant par le poids le plus faible. Il n’a évidemment pas d’intérêt autre que didactique, cette fonctionnalité étant native dans tous les langages.
def show_decimals(n):while n > 0:n, r = euclidean_division(n, 10)yield r>>> print(list(show_decimals(123)))[3, 2, 1]
Questions :
0123456789abcdef
)Pour coder des données binaires dans un document texte (par exemple, des images directement dans le code HTML), le codage base64 est souvent utilisé. Concrètement, cela consiste à utiliser les 64 caractères suivant comme chiffres, chacun pouvant encoder 6 bits d’information () :
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
Le flux de données à encoder étant généralement des octets, l’implémentation présente toutefois quelques subtilités :
=
est ajouté
à la fin de la chaîne encodée pour chaque octet manquant (pour arriver à un nombre multiple de 3)Par exemple, en utilisant la librairie b64encode :
from base64 import b64encode>>> b64encode(b"foo")'Zm9v'>>> b64encode(b"Je pense donc je suis.")'SmUgcGVuc2UgZG9uYyBqZSBzdWlzLg=='
Questions :
Combien de symboles = y aura-t-il en fin de chaîne pour b64encode(b"a")
?
Même question avec b64encode("à".encode("utf-8"))
?
L’algorithme Base85 encode les séquence de 32 bits en séquences de caractères,
utilisant un alphabet de caractères.
Quelle est la valeur minimale pour ?
Une variante de cet algorithme est utilisée par ZeroMQ.
On appelle PGCD (plus grand commun diviseur) de deux entiers non nuls et (noté ) le plus grand entier qui divise simultanément et .
Par exemple :
Le résultat qui suit est plus compliqué que la division euclidienne. Si vous avez des difficultés à l’appréhender, c’est tout à fait normal. Il est néanmoins à la base d’une bonne partie de l’arithmétique des entiers et sa preuve peut aussi se faire via un algorithme, raison de plus pour en parler ici 😊
Identité de Bézout
Il existe deux nombres tels que :
Par exemple :
L’algorithme d’Euclide permet de calculer le PGCD de deux nombres par une méthode itérative, et l’analyse de son fonctionnement met en évidence l’identité de Bézout.
En voici une implémentation en Python :
def gcd(a, b):while b != 0:q, r = euclidean_division(a, b)a, b = b, rreturn a
Analyse de l’algorithme :
Pour finir, nous allons énoncer deux résultats fondamentaux sur la structure des nombres entiers. Un lemme préalable est utile pour les démontrer.
Lemme d’Euclide
Si un nombre premier divise , alors divise ou divise .
Ce lemme peut se prouver à l’aide de l’identité de Bézout, en supposant que ne divise pas (on montre alors qu’il divise forcément ). Comme est premier, on a alors et on peut construire des entiers vérifiant :
On en déduit , et donc divise car il divise chacun des deux termes de la somme.
Théorème fondamental de l’arithmétique
Tout nombre entier peut s’écrire de façon unique comme produit de nombres premiers.
Par exemple :
L’algorithme suivant permet d’obtenir cette décomposition (il est cependant assez inefficace) :
def prime_factors(n):f = 2while n > 1:q, r = euclidean_division(n, f) # n = q * f + rif r == 0:yield fn = qelse:f += 1>>> print(list(prime_factors(289674)))[2, 3, 3, 7, 11, 11, 19]
Cet algorithme fonctionne sur le principe suivant :
Question : Montrer que la décomposition obtenue est unique, c’est-à-dire que chaque nombre premier apparaît toujours le même nombre de fois dans la décomposition en produit.
Il existe une infinité de nombres premiers.
Ce résultat peut se prouver en raisonnant par l’absurde.
On suppose qu’il existe seulement un nombre fini de nombres premiers , et on note .
n’est divisible par aucun de ces nombres (le reste de la division euclidienne est toujours ), ce qui est en contradiction avec l’existence d’une décomposition de en produit de nombres premiers.
💻 On pourra d’ailleurs illustrer cette démonstration en utilisant Python, la décomposition de avec différentes valeurs pour pouvant être mise en évidence :
>>> print(list(prime_factors(2*3 + 1)))[7]>>> print(list(prime_factors(2*5*13*19 + 1)))[7, 353]>>> print(list(prime_factors(3*5*13*19 + 1)))[2, 17, 109]
Comme vous le savez, les nombres ne s’arrêtent pas aux entiers 😉
Je vous propose de continuer avec cet article sur la construction des nombres réels, toujours illustré avec Python.
Maths et applications, avec les mains et avec du code 💻
Suivre sur Twitter