Contenu:
Image : http://pikabu.ru/
Introduction
Dès les premiers jours de mon apprentissage de Java, je suis tombé sur un type de primitives aussi curieux que les nombres à virgule flottante. J'ai tout de suite été intéressé par leurs fonctionnalités et, plus encore, par la façon dont ils étaient écrits en code binaire (qui est interconnecté). Contrairement à toute plage d’entiers, même dans une très petite plage (par exemple de 1 à 2), il en existe un nombre infini. Et ayant une taille de mémoire finie, il est impossible d’exprimer cet ensemble. Alors, comment sont-ils exprimés en binaire et comment fonctionnent-ils ? Hélas, les explications sur
le wiki et un article plutôt sympa sur Habré
ici ne m'ont pas donné une compréhension complète, même s'ils ont posé les bases. La prise de conscience n’est venue qu’après avoir lu cet
article d’analyse le lendemain de sa lecture.
Excursion dans l'histoire
(
extrait de cet article sur Habré ) Dans les années 60 et 70, lorsque les ordinateurs étaient grands et les programmes petits, il n'existait pas encore de norme unique pour les calculs, ni de norme pour exprimer le nombre à virgule flottante lui-même. Chaque ordinateur le faisait différemment et chacun avait ses propres erreurs. Mais au milieu des années 70, Intel a décidé de fabriquer de nouveaux processeurs prenant en charge l'arithmétique « améliorée » et en même temps de la standardiser. Les professeurs William Kahan et John Palmer (non, pas l'auteur de livres sur la bière) ont été sollicités pour le développer. Il y a eu quelques drames, mais une nouvelle norme a été élaborée. Désormais, cette norme s'appelle IEEE754
Format de nombre à virgule flottante
Même dans les manuels scolaires, tout le monde était confronté à une manière inhabituelle d'écrire des nombres très grands ou très petits de la forme
1,2 × 10 3 ou
1,2 E3 , ce qui équivaut à
1,2 × 1000 = 1200 . C'est ce qu'on appelle la méthode de notation exponentielle. Dans ce cas, il s'agit de l'expression d'un nombre par la formule :
N=M×n p , où
- N = 1200 - le nombre résultant
- M = 1,2 - mantisse - partie fractionnaire, sans tenir compte des commandes
- n = 10 est la base de la commande. Dans ce cas et quand on ne parle pas d'ordinateurs, la base est le chiffre 10
- p = 3 - degré de base
Très souvent, la base de l'ordre est supposée être 10
et seules la mantisse et la valeur de la base sont écrites, en les séparant par la lettre
E. Dans notre exemple, j'ai donné des entrées équivalentes
1,2 × 10 3 et
1,2 E3 . Si tout est clair et que nous avons terminé l'excursion nostalgique dans le programme scolaire, je recommande maintenant d'oublier cela, car lors de la formation d'un nombre à virgule flottante, nous avons affaire à puissances de deux, pas de dizaines, c'est-à-dire
n = 2 , toute la formule harmonieuse
1.2E3 s'effondre et cela m'a vraiment brisé le cerveau.
Signe et diplôme
Alors qu'est-ce que nous avons? En conséquence, nous avons également un nombre binaire, qui consiste en
une mantisse - la partie que nous élèverons à une puissance et la puissance elle-même. De plus, comme c'est souvent le cas avec les types entiers, les nombres à virgule flottante ont un bit qui détermine le signe - si le nombre sera positif ou négatif. A titre d'exemple, je propose de considérer le type
float
, qui se compose de 32 bits. Avec les nombres à double précision,
double
la logique est la même, sauf qu’il y a deux fois plus de bits. Parmi les 32 bits, le premier poids fort est attribué au signe, les 8 bits suivants sont attribués à l'exposant - la puissance à laquelle nous élèverons la mantisse, et les 23 bits restants - à la mantisse. Pour le démontrer, regardons un exemple :
Le premier bit est très simple. Si la valeur du premier bit
est 0 , alors le nombre que nous obtiendrons sera
positif . Si le bit est
1 , alors le nombre sera
négatif . Le bloc suivant de 8 bits est un bloc exposant. L'exposant est écrit sous la forme d'un nombre régulier
de huit bits , et pour obtenir le degré requis, nous devons soustraire
127 du nombre obtenu . Dans notre cas, les huit bits de l'exposant sont
10000001 . Cela correspond au nombre
129 . Si vous avez une question sur la façon de calculer cela, l'image montre une réponse rapide. Une version étendue peut être obtenue dans n'importe quel cours d'algèbre booléenne.
1×2 7 + 0×2 6 + 0×2 5 + 0×2 4 + 0×2 3 + 0×2 2 + 0×2 1 + 1×2 0 = 1×128 + 1×1 = 128+ 1=129 Il n'est pas difficile de calculer que le nombre maximum que nous pouvons obtenir de ces 8 bits est
11111111 2 = 255 10 (les indices
2 et
10 signifient des systèmes de nombres binaires et décimaux) Cependant, si nous utilisons uniquement des valeurs d'exposants positifs (
de 0 à 255 ), alors les nombres résultants auront plusieurs nombres avant la virgule décimale, mais pas après ? Pour obtenir des valeurs négatives du degré, vous devez soustraire
127 de l'exposant généré . Ainsi, la plage de degrés sera
de -127 à 128 . En utilisant notre exemple, le degré requis sera
129-127 = 2 . Retenons ce numéro pour l'instant.
Mantisse
Parlons maintenant de la mantisse. Il se compose de 23 bits, mais au début il y a toujours une autre unité implicite, pour laquelle les bits ne sont pas alloués. Ceci est fait pour des raisons d'opportunité et d'économie. Le même nombre peut être exprimé avec différentes puissances en ajoutant des zéros à la mantisse avant ou après la virgule décimale. La façon la plus simple de comprendre cela est d'utiliser un exposant décimal :
120 000 = 1,2×10 5 = 0,12×10 6 = 0,012×10 7 = 0,0012×10 8 etc. Cependant, en entrant un nombre fixe en tête de la mantisse, nous recevrons à chaque fois de nouveaux nombres. Prenons pour acquis qu'avant nos 23 bits, il y en aura un de plus avec un. Habituellement, ce bit est séparé du reste par un point, ce qui ne veut cependant rien dire. C'est juste plus pratique 1. 1110000000000000000000000
Maintenant, la mantisse résultante doit être élevée à une puissance de gauche à droite, en diminuant la puissance d'un à chaque pas. On part de la valeur de la puissance que l'on a obtenue à la suite du calcul, soit
2 (j'ai volontairement choisi un exemple simple pour ne pas écrire chaque valeur de la puissance de deux et je ne les ai pas calculées dans le tableau ci-dessus lorsque le le bit correspondant est zéro)
1×2 2 + 1×2 1 + 1×2 0 + 1×2 -1 = 1×4 + 1×2 + 1×1 + 1×0,5 = 4+2+1+0,5 = 7.5 et j'ai obtenu le résultat
7.5 , l'exactitude peut être vérifiée, par exemple, sur
ce lien
Résultats
Un nombre à virgule flottante standard
float
se compose de 32 bits, le premier bit est le signe (+ ou -), les huit suivants sont l'exposant, les 23 suivants sont la mantisse Par signe - si le bit 0 est un nombre positif. Si le bit 1 est négatif.
Par exponentiel - nous convertissons au niveau du bit en un nombre décimal (le premier bit en partant de la gauche est
128 , le deuxième est
64 , le troisième est
32 , le quatrième est
16 , le cinquième est
8 , le sixième est
4 , le septième est
2 , le huitième est
1 ), soustrayez
127 du nombre résultant , nous obtenons le degré avec lequel nous allons commencer.
Selon la mantisse - aux 23 bits existants devant, nous ajoutons un autre bit avec la valeur 1 et à partir de celui-ci, nous commençons à augmenter la puissance que nous avons reçue, en décrémentant cette puissance à chaque bit suivant.
C'est tout, les amis, les enfants ! PS : En guise de devoir, à l'aide de cet article, laissez dans les commentaires vos versions des raisons pour lesquelles des erreurs de précision se produisent avec un grand nombre d'opérations arithmétiques avec des nombres à virgule flottante
GO TO FULL VERSION