Quel est le plus petit nombre supérieur à 0? C’est l’une de ces questions simples avec des réponses compliquées quelque part entre « il n’y en a pas » et « cela dépend ».
Si vous demandez à un mathématicien, il vous dira qu’il ne peut pas y avoir un tel nombre car cela briserait les mathématiques. Si vous avez un nombre n, où n est le plus petit nombre après 0, il ne peut pas y avoir de nombre n / 2, car n est déjà le plus petit. Cela signifie que la division elle-même se décompose, ce que les mathématiciens n’aiment pas.
Si vous demandez à un ordinateur, vous obtiendrez une réponse. Contrairement au monde réel, les ordinateurs n’ont pas une quantité infinie de nombres car ils ne pouvaient tout simplement pas tenir. Les ordinateurs stockent des numéros dans des registres de mémoire et chaque registre a un nombre fixe de bits. Imaginez si vous n’aviez que trois chiffres. Le plus grand nombre que vous pourriez représenter serait 999. C’est ce qui se passe dans un ordinateur.
Cela signifie que l’ensemble des entiers dans un ordinateur est limité par le nombre de chiffres. Dans un ordinateur, il y a certainement un plus grand nombre (par exemple, INT_MAX
en C). C’est le nombre avec le nombre maximum de chiffres, qui sont tous définis sur un binaire 1
. Sur un système 8 bits, ce nombre serait 11111111
.
Nous pouvons compliquer encore plus les choses en incluant des nombres négatifs. Si nous avons 8 bits de données, nous pouvons utiliser le premier bit pour représenter le signe du nombre. 0
pour plus et 1
pour moins. Maintenant, nous avons 7 bits pour nos chiffres, donc le plus grand nombre est 011111111
qui est plus petit que notre plus grand nombre précédent.
Nous n’avons toujours pas terminé. Nous devons également représenter des nombres décimaux. Même si 0,12 est un petit nombre, il a toujours trois chiffres, tout comme 123. La différence est qu’il y a encore une chose à laquelle nous devons penser: le point décimal, également appelé point radix. Nous devons stocker à la fois les chiffres et la position du point radix.
Alors que les entiers sont limités dans leur taille, les nombres décimaux sont limités en taille et en précision. Si vous avez un nombre fixe de chiffres, il n’y a que tant de chiffres que vous pouvez mettre après le point décimal. C’est pourquoi les ordinateurs doivent arrondir les nombres décimaux.
Comment stockons-nous ces nombres décimaux, alors? Les ordinateurs ne comprennent que les entiers, nous avons donc besoin d’un moyen de stocker un nombre décimal uniquement en utilisant des entiers.
Disons que nous avons le nombre 3.14
. Commençons par écrire tous les chiffres du nombre. Nous obtenons 314
. C’est un début. Nous savons qu’en multipliant par des puissances de 10, nous pouvons « déplacer » le point décimal autour du nombre. 314 * 10^-1
vaut 31,4, tandis que 314 * 10^-2
vaut 3,14.
Tout ce dont nous avons besoin pour représenter le nombre 3.14 est de trois entiers: 314, 10 et -2. 314 est ce qu’on appelle un significand, et ce sont tous les chiffres du nombre écrit.
10 est appelé un radix ou une base. Nous savons qu’en multipliant par des puissances de 10, nous pouvons déplacer le point décimal autour des nombres en base 10. La même chose fonctionne pour toutes les bases de nombres: en base 2 (ou binaire), vous pouvez déplacer le point en multipliant par des puissances de 2.
La puissance par laquelle nous passons est appelée l’exposant, et elle nous indique où se trouve le point décimal.
Vous pouvez écrire chaque nombre décimal comme ces trois nombres avec une formule simple:
number = significand * base^exponent3.14 = 314 * 10^-2
32.8 = 328 * 10^-1
Un ordinateur stocke un nombre décimal en stockant le signe, l’exposant et le significand dans une seule chaîne de chiffres de 32 ou 64 bits. Habituellement, il y a 1 bit pour le signe, 11 bits pour stocker l’exposant et 53 bits pour stocker le significand, en ajoutant jusqu’à 64.
Dans cet esprit, revenons à notre question: Quel est le plus petit nombre non nul? Si nous n’avons que trois chiffres, le plus petit nombre possible est 0,01. Avec quatre chiffres, c’est 0,001. Vous remarquerez un modèle ici: le significand est toujours le même, seul l’exposant change.
Ce dont nous avons besoin est un significand de 1
, car c’est le plus petit après 0
. Nous devons ensuite déplacer le point décimal aussi loin que possible vers la gauche. Pour ce faire, nous avons besoin du plus petit exposant possible (le plus négatif).
La taille dépend de la disposition du nombre en mémoire. Si nous avons 11 bits pour l’exposant, nous ne pouvons écrire qu’un nombre de 10 bits de long, avec 1 bit réservé au signe. Dans un système 64 bits, le plus petit exposant est -308
.
Au final, le plus petit nombre possible dans un système 64 bits serait d’environ 1 * 10^-308
. C’est petit !
Nous avons établi qu’il y a un plus petit nombre. Ce chiffre nous indique à quel point nous pouvons faire confiance à notre ordinateur. Si vous faites quelque chose qui nécessite de très grands nombres ou des nombres très précis, vous devez garder ce nombre à l’esprit.
Ce que nous venons de calculer est quelque chose appelé l’unité en dernier lieu, ou ulp, de 0. En plus d’être un mot vraiment cool, ulp nous indique quelle est la distance minimale entre deux nombres dans un ordinateur. Nous avons calculé l’ulp de 0, qui est la distance minimale entre 0 et le nombre suivant.
Si vous ajoutez la valeur calculée à 0 et essayez de les comparer, ils ne seraient pas le même nombre. Cependant, si vous ajoutez une valeur inférieure à l’ulp, ce serait toujours le même nombre en ce qui concerne l’ordinateur.
print(0 == 0 + ulp(0)) // false
print(0 == 0 + ulp(0) / 2) // true
Pour nous, il est évident que l’ajout d’une valeur non nulle à un nombre produira un nombre différent, mais un ordinateur doit arrondir quelque part, il ne peut donc pas nécessairement dire si deux nombres sont identiques.
Pour comparer plus facilement les systèmes informatiques, nous utilisons l’ulp de 1, et l’appelons la machine epsilon. Une fois que vous connaissez la machine epsilon, vous pouvez calculer n’importe quel autre ulp avec la formule suivante:
ulp(x) = machine epsilon * radix^exponent(x)
La valeur que nous avons calculée est très petite, vous n’atteindrez donc probablement pas cette limite lors du codage. Mais, nous avons calculé la valeur pour 0. Avec plus de chiffres nécessaires pour le côté gauche du point décimal, moins nous en avons pour le côté droit. Cela signifie que plus le nombre est grand, moins vous avez de précision. En d’autres termes, l’ulp est une fonction directe de l’exposant. Lorsque vous déplacez le point décimal vers la droite, l’ulp augmente et vous perdez de la précision.
J’espère que ces informations vous aideront la prochaine fois que vous obtiendrez une étrange erreur à virgule flottante dans votre code. Rappelez-vous, les ordinateurs sont assez puissants, mais même un ordinateur a ses limites.