251 votes

Pourquoi les nombres à virgule flottante sont inexactes ?

Pourquoi certains numéros de perdre de la précision lorsqu'ils sont stockés comme des nombres à virgule flottante?

Par exemple, le nombre décimal 9.2 peut être exprimé exactement comme un rapport de deux entiers décimaux (92/10), à la fois de ce qui peut être exprimé exactement en binaire (0b1011100/0b1010). Toutefois, le même rapport stockées en tant que nombre à virgule flottante n'est jamais exactement égale à 9.2:

32-bit "single precision" float: 9.19999980926513671875
64-bit "double precision" float: 9.199999999999999289457264239899814128875732421875

Comment une telle apparemment simple numéro de "trop gros" pour exprimer en 64 bits de la mémoire?

304voto

mhlester Points 13301

Dans la plupart des langages de programmation, des nombres à virgule flottante sont représentés un peu comme de la notation scientifique: avec un exposant et la mantisse (aussi appelé le significande). Un très simple nombre, dire 9.2, est en fait cette fraction:

5179139571476070 * 2 -49

Où l'exposant est - -49 et la mantisse est - 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 entiers. En d'autres termes, tous les flotteurs doit être un nombre entier multiplié par une puissance entière de 2.

9.2 peut-être tout simplement 92/10, mais 10 ne peut pas être exprimé comme 2n si n est limitée à des valeurs entières.


Voir les Données

Tout d'abord, quelques fonctions pour voir les composants de 32 - et 64-bit float. Brillant sur ces si vous ne s'intéressent qu'à la sortie (par 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é inhérente à cette fonction, et que ce serait bien de la tangente à expliquer, mais si vous êtes intéressés, la ressource importante pour nous, c'est l' struct module.

Python float est un 64 bits, nombre double précision. Dans d'autres langages tels que C, C++, Java et C#, double précision a un type distinct double, ce qui est souvent mis en œuvre en version 64 bits.

Lorsque nous appeler cette fonction avec notre exemple, 9.2, voici ce que nous obtenons:

>>> float_to_bin_parts(9.2)
['0', '10000000010', '0010011001100110011001100110011001100110011001100110']

L'interprétation des Données

Vous verrez que j'ai divisé la valeur de retour en trois volets. Ces composantes sont les suivantes:

  • Signe
  • Exposant
  • Mantisse (également appelé Significande, ou une Fraction)

Signe

Le signe est stocké dans le premier composant que d'un seul bit. Il est facile à expliquer: - 0 signifie que le flotteur est un nombre positif; 1 signifie qu'il est négatif. Parce qu' 9.2 est positif, notre signe de la valeur est 0.

Exposant

L'exposant est stocké dans le milieu de la composante de 11 bits. Dans notre cas, 0b10000000010. En décimal, ce qui représente la valeur 1026. Un caprice de cette composante est que vous devez soustraire un nombre égal à 2(nombre de bits) - 1 - 1 afin d'obtenir la valeur de l'exposant; dans notre cas, cela signifie que la soustraction 0b1111111111 (nombre décimal 1023) afin d'obtenir la valeur de l'exposant, 0b00000000011 (nombre décimal 3).

Mantisse

La mantisse est stocké dans le troisième volet de 52 bits. Cependant, il y a une bizarrerie de ce composant. Pour comprendre cette bizarrerie, considérons un nombre en notation scientifique, comme ceci:

6.0221413x1023

La mantisse serait l' 6.0221413. Rappelons que la mantisse en notation scientifique commence toujours avec un seul non-chiffre zéro. La même chose vaut pour les binaires, sauf que le binaire n'a que deux chiffres: 0 et 1. De sorte que le binaire mantisse toujours commence avec 1! Quand un flotteur est stockée, l' 1 à l'avant de la binaire mantisse est omis pour économiser de l'espace; nous avons à le replacer à l'avant de notre troisième élément pour obtenir le vrai mantisse:

1.0010011001100110011001100110011001100110011001100110

Cela implique plus qu'une simple addition, parce que les bits stockés dans notre troisième élément représentent les fractions de la partie de la mantisse, à droite de la radix point.

Lorsque vous traitez avec des nombres décimaux, nous "déplacer 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. Depuis notre troisième élément a 52 bits, on divise par 252 pour le déplacer 52 places vers la droite:

0.0010011001100110011001100110011001100110011001100110

En notation décimale, c'est la même chose que diviser 675539944105574 par 4503599627370496 pour obtenir de l' 0.1499999999999999. (C'est un exemple d'un rapport qui peut être exprimé exactement en binaire, mais seulement environ en décimal; pour plus de détails, voir: 675539944105574 / 4503599627370496.)

Maintenant que nous avons transformé le troisième composant dans un nombre fractionnaire, l'ajout d' 1 donne le vrai de la mantisse.

Récapitulatif sur les Composants

  • Signe (première composante): 0 pour le positif, 1 pour les négatifs
  • L'exposant (composant intermédiaire): Soustraire 2(nombre de bits) - 1 - 1 afin d'obtenir la valeur de l'exposant
  • Mantisse (dernier volet): Diviser par 2(nombre de bits) et ajouter 1 afin d'obtenir la valeur de la mantisse

Le calcul du Nombre

Mettre ensemble des trois parties, nous nous sommes donné ce nombre binaire:

1.0010011001100110011001100110011001100110011001100110 x 1011

Que nous pouvons ensuite convertir de binaire en décimal:

1.1499999999999999 x 23 (inexact!)

Et de se multiplier pour révéler la dernière représentation du nombre, nous avons commencé avec (9.2) après avoir été stockée en tant que valeur en virgule flottante:

9.1999999999999993


Représentant qu'une Fraction

9.2

Maintenant que nous avons établi le nombre, il est possible de le reconstruire en une fraction simple:

1.0010011001100110011001100110011001100110011001100110 x 1011

Maj de la mantisse d'un nombre entier:

10010011001100110011001100110011001100110011001100110 x 1011-110100

Convertir en décimal:

5179139571476070 x 23-52

Soustraire l'exposant:

5179139571476070 x 2-49

Tourner à exposant négatif de la division:

5179139571476070 / 249

Multiplier exposant:

5179139571476070 / 562949953421312

Ce qui équivaut à:

9.1999999999999993

9.5

>>> float_to_bin_parts(9.5)
['0', '10000000010', '0011000000000000000000000000000000000000000000000000']

Vous pouvez déjà voir la mantisse n'est qu'à 4 chiffres suivis par tout un tas de zéros. Mais nous allons aller aux rythmes de la musique.

Assembler le binaire notation scientifique:

1.0011 x 1011

Déplacer le point décimal:

10011 x 1011-100

Soustraire l'exposant:

10011 x 10-1

Binaire à décimal:

19 x 2-1

L'exposant négatif de la division:

19 / 21

Multiplier exposant:

19 / 2

Est égal à:

9.5



Lectures complémentaires

44voto

SchighSchagh Points 3025

Ce n'est pas une réponse complète (mhlester déjà couvert beaucoup de bonne terre, je ne vais pas en double), mais je tiens à souligner combien la représentation d'un nombre dépend de la base, vous travaillez en.

Considérons la fraction 2/3

En bon ol' base 10, en général, nous l'écrire quelque chose comme

  • 0.666...
  • 0.666
  • En regard de 0,667

Lorsque nous regardons ces représentations, nous avons tendance à associer chacun d'eux avec la fraction 2/3, même si seule la première représentation est mathématiquement égale à la fraction. La deuxième et la troisième représentation/approximations y a une erreur sur l'ordre de 0,001, qui est en fait bien pire que l'erreur entre 9,2 et 9.1999999999999993. En fait, la seconde représentation n'est même pas arrondi correctement! Néanmoins, nous n'avons pas de problème avec 0.666 comme une approximation du nombre 2/3, donc nous ne devrions pas vraiment un problème avec la manière dont 9.2 est approchée dans la plupart des programmes. (Oui, dans certains programmes.)

Nombre de bases de

Donc voilà où nombre de bases sont crutial. Si nous avons essayé de représenter les 2/3 de la base de 3, puis

(2/3)10 = 0.23

En d'autres termes, nous avons exacte, finie la représentation, pour le même nombre par commutation de base! Le take-away est que même si vous pouvez convertir n'importe quel nombre de n'importe quelle base, tous les nombres rationnels sont exactes finis représentations dans certaines bases, mais pas dans d'autres.

Pour conduire ce point, examinons 1/2. Il pourrait vous surprendre que même si c'parfaitement simple nombre exact, la représentation en base 10 et de 2, il nécessite une répétition de la représentation en base 3.

(1/2)10 = 0.510 = 0.12 = 0.1111 comme...3

Pourquoi sont des nombres à virgule flottante inexactes?

Parce que souvent, ils sont l'approximation des nombres rationnels qui ne peut être représenté finitely en base 2 (les chiffres de répétition), et en général ils sont de rapprochement réel (éventuellement irrationnel) les nombres qui ne peuvent pas être représentable dans finitely nombre de chiffres dans toute la base.

16voto

LumpN Points 2989

Bien que toutes les réponses sont bonnes il y a encore une chose qui manque:

Il est impossible de représenter les nombres irrationnels (par exemple π, sqrt(2), log(3), etc.) justement!

Et qui en réalité est pourquoi ils sont appelés irrationnel. Aucune quantité de bits de stockage dans le monde serait assez pour tenir l'un d'entre eux. Seulement symbolique de l'arithmétique est en mesure de préserver leur précision.

Bien que si vous vous limitez mathématiques besoins de nombres rationnels seulement le problème de la précision devient gérable. Vous devez stocker une paire de (peut-être très grand) des entiers a et b pour contenir le nombre représenté par la fraction a/b. Tous vos arithmétique serait de le faire sur les fractions comme au lycée des mathématiques (par exemple, a/b * c/d = ac/bd).

Mais bien sûr, vous auriez encore fonctionner dans le même genre de problème quand pi, sqrt, log, sin, etc. sont impliqués.

TL;DR

Pour l'accélération matérielle de l'arithmétique d'un nombre limité de nombres rationnels peuvent être représentés. Tous les non-représentable nombre est approximatif. Quelques chiffres (c'est à dire irrationnel) ne peuvent jamais être représentés quel que soit le système.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X