Dans la plupart des langages de programmation, les nombres à virgule flottante sont représentés un peu comme la notation scientifique : avec un exposant et une mantisse (également appelée significande). Un nombre très simple, disons 9.2
, est en fait cette fraction:
5179139571476070 * 2 -49
Où se trouve l'exposant -49
et la mantisse 5179139571476070
. La raison pour laquelle il est impossible de représenter certains nombres décimaux de cette façon est que l'exposant et la mantisse doivent être des nombres entiers. En d'autres termes, tous les flottants doivent être un entier multiplié par un puissance entière de 2 .
9.2
peut être simplement 92/10
, mais 10 ne peut pas être exprimé comme 2 n si n est limité à des valeurs entières.
Voir les données
Tout d'abord, quelques fonctions pour voir les composants qui font un 32 et 64 bits float
. Brossez-les si vous ne vous souciez que de la sortie (exemple en Python):
def float_to_bin_parts(number, bits=64):
if bits == 32: # single precision
int_pack = 'I'
float_pack = 'f'
exponent_bits = 8
mantissa_bits = 23
exponent_bias = 127
elif bits == 64: # double precision. all python floats are this
int_pack = 'Q'
float_pack = 'd'
exponent_bits = 11
mantissa_bits = 52
exponent_bias = 1023
else:
raise ValueError, 'bits argument must be 32 or 64'
bin_iter = iter(bin(struct.unpack(int_pack, struct.pack(float_pack, number))[0])[2:].rjust(bits, '0'))
return [''.join(islice(bin_iter, x)) for x in (1, exponent_bits, mantissa_bits)]
Il y a beaucoup de complexité derrière cette fonction, et ce serait assez tangent à expliquer, mais si vous êtes intéressé, la ressource importante pour nos besoins est la module struct .
Python float
est un nombre 64 bits à double précision. Dans d'autres langages tels que C, C ++, Java et C #, la double précision a un type distinctdouble
, qui est souvent implémenté en 64 bits.
Lorsque nous appelons cette fonction avec notre exemple 9.2
, voici ce que nous obtenons:
>>> float_to_bin_parts(9.2)
['0', '10000000010', '0010011001100110011001100110011001100110011001100110']
Interprétation des données
Vous verrez que j'ai divisé la valeur de retour en trois composants. Ces composants sont:
- Signe
- Exposant
- Mantissa (également appelée Significand ou Fraction)
Signe
Le signe est stocké dans le premier composant en tant que bit unique. C'est facile à expliquer: 0
signifie que le flotteur est un nombre positif; 1
signifie que c'est négatif. Parce que 9.2
c'est positif, notre valeur de signe est0
.
Exposant
L'exposant est stocké dans le composant central sous forme de 11 bits. Dans notre cas 0b10000000010
,. En décimal, cela représente la valeur 1026
. Une particularité de ce composant est que vous devez soustraire un nombre égal à 2 (# de bits) - 1 - 1 pour obtenir le véritable exposant; dans notre cas, cela signifie soustraire 0b1111111111
(nombre décimal 1023
) pour obtenir le véritable exposant,0b00000000011
(nombre décimal 3).
Mantissa
La mantisse est stockée dans le troisième composant sous 52 bits. Cependant, il y a aussi une bizarrerie à ce composant. Pour comprendre cette bizarrerie, considérez un nombre en notation scientifique, comme ceci:
6.0221413x10 23
La mantisse serait la 6.0221413
. Rappelons que la mantisse en notation scientifique commence toujours par un seul chiffre non nul. Il en va de même pour le binaire, sauf que le binaire n'a que deux chiffres: 0
et 1
. La mantisse binaire commence donc toujours par 1
! Lorsqu'un flottant est stocké, le 1
devant de la mantisse binaire est omis pour économiser de l'espace; nous devons le replacer à l'avant de notre troisième élément pour obtenir la vraie mantisse:
1.0010011001100110011001100110011001100110011001100110
Cela implique plus qu'un simple ajout, car les bits stockés dans notre troisième composant représentent en fait la partie fractionnaire de la mantisse, à droite du point radix .
Lorsque nous traitons des nombres décimaux, nous "déplaçons le point décimal" en multipliant ou en divisant par des puissances de 10. En binaire, nous pouvons faire la même chose en multipliant ou en divisant par des puissances de 2. Puisque notre troisième élément a 52 bits, nous divisons par 2 52 pour le déplacer 52 places vers la droite:
0,0010011001100110011001100110011001100110011001100110
En notation décimale, cela revient à diviser 675539944105574
par 4503599627370496
pour obtenir 0.1499999999999999
. (Ceci est un exemple d'un rapport qui peut être exprimé exactement en binaire, mais seulement approximativement en décimal; pour plus de détails, voir: 675539944105574/4503599627370496 .)
Maintenant que nous avons transformé le troisième composant en nombre fractionnaire, l'ajout 1
donne la vraie mantisse.
Récapitulation des composants
- Signe (premier composant):
0
pour positif, 1
pour négatif
- Exposant (composante centrale): Soustraire 2 (# de bits) - 1-1 pour obtenir le véritable exposant
- Mantisse (dernier composant): divisez par 2 (# de bits) et ajoutez
1
pour obtenir la vraie mantisse
Calcul du nombre
En réunissant les trois parties ensemble, on nous donne ce numéro binaire:
1,0010011001100110011001100110011001100110011001100110 x 10 11
Que nous pouvons ensuite convertir du binaire en décimal:
1,149999999999999999 x 2 3 (inexact!)
Et multipliez pour révéler la représentation finale du nombre que nous avons commencé avec ( 9.2
) après avoir été stocké en tant que valeur à virgule flottante:
9.1999999999999993
Représenter comme une fraction
9.2
Maintenant que nous avons construit le nombre, il est possible de le reconstruire en une fraction simple:
1,0010011001100110011001100110011001100110011001100110 x 10 11
Décalez la mantisse en un nombre entier:
10010011001100110011001100110011001100110011001100110 x 10 11-110100
Convertir en décimal:
5179139571476070 x 2 3-52
Soustrayez l'exposant:
5179139571476070 x 2 -49
Transformez l'exposant négatif en division:
5179139571476070/2 49
Exposant multiplié:
5179139571476070/562949953421312
Ce qui équivaut à:
9.1999999999999993
9.5
>>> float_to_bin_parts(9.5)
['0', '10000000010', '0011000000000000000000000000000000000000000000000000']
Déjà, vous pouvez voir que la mantisse n'est que de 4 chiffres, suivie de beaucoup de zéros. Mais passons à travers les allures.
Assemblez la notation scientifique binaire:
1,0011 x 10 11
Décalez le point décimal:
10011 x 10 11-100
Soustrayez l'exposant:
10011 x 10 -1
Binaire à décimal:
19 x 2 -1
Exposant négatif de la division:
19/2 1
Exposant multiplié:
19/2
Équivaut à:
9.5
Lectures complémentaires