Maison > Article > développement back-end > Une brève discussion sur les raisons pour lesquelles les opérations en virgule flottante produisent des erreurs
Cet article utilise Python comme exemple pour expliquer pourquoi les opérations en virgule flottante produisent des erreurs ? Veuillez présenter les circonstances dans lesquelles des erreurs peuvent survenir ? et comment le résoudre ? J'espère que ça aide.
[Recommandation associée : Tutoriel vidéo Python3 ]
Tout le monde rencontrera la soi-disant erreur de virgule flottante lors de l'écriture de code. Si vous n'êtes pas entré dans le gouffre de l'erreur de virgule flottante, je peux seulement dire que. tu as trop de chance.
Prenons le Python dans l'image ci-dessous comme exemple. 0.1 + 0.2
n'est pas égal à 0.3
, et 8.7 / 10
n'est pas égal à 0.87
, mais 0.869999…
C'est vraiment étrange
Mais ce n'est certainement pas un bug des enfers. , et il n'y a pas non plus de problème avec la conception de Python. C'est le résultat inévitable des nombres à virgule flottante lors de l'exécution d'opérations, donc c'est la même chose même en JavaScript ou dans d'autres langages :
Parlons de pourquoi il existe Avant de parler des erreurs à virgule flottante, parlons de la façon dont les ordinateurs utilisent 0 et 1 pour représenter un entier Tout le monde devrait connaître le binaire : par exemple, 101
représente 2^2 + 2. ^0$, soit 5, 1010
représente 2^3 + 2^1$ soit 10.
S'il s'agit d'un entier non signé de 32 bits, cela signifie qu'il a 32 positions où 0 ou 1 peut être placé, donc la valeur minimale est 0000...0000
, qui est 0, et la valeur maximale 1111...1111
représente 2 $^{ 31} + 2^{ 30} + ... + 2^1 + 2^0$, soit 4294967295
Du point de vue de la permutation et de la combinaison, car chaque bit peut être 0 ou 1, la valeur de la variable entière est de 2 $^{32} $ de possibilités, il peut donc avec précision exprimer n'importe quelle valeur entre 0 et $2^{23} - 1$ sans aucune erreur.
Bien qu'il existe de nombreux entiers de 0 à $2^{23} - 1$, leur nombre est limité après tout, qui peut atteindre 2$^{32}$ Un seul mais flottant- ; les nombres ponctuels sont différents. On peut y penser de cette façon : il n'y a que dix entiers compris entre 1 et 10, mais il existe une infinité de nombres à virgule flottante, comme 5.1, 5.11, 5.111, etc., c'est impossible. pour les énumérer. Mais comme il n'y a que 2³² possibilités dans l'espace 32 bits, afin d'insérer tous les nombres à virgule flottante dans cet espace 32 bits, de nombreux fabricants de processeurs ont inventé diverses méthodes de représentation des nombres à virgule flottante, mais si chaque processeur Les formats sont tous différents et encombrants, donc en fin de compte, la norme IEEE 754 publiée par l'IEEE a été utilisée comme norme générale de calcul en virgule flottante. Les processeurs d'aujourd'hui sont également conçus selon cette norme.
IEEE 754
En prenant le nombre à virgule flottante 8,5 comme exemple, si vous souhaitez le changer au format IEEE 754, vous devez d'abord faire une certaine normalisation : diviser 8,5 en 8 + 0,5, soit 2^3 + (cfrac{1}{ 2}) ^1$, puis écrit en binaire, il devient , et enfin écrit sous la forme $1,0001 fois 2^3$, ce qui est très similaire à la notation scientifique décimale.
1000.1
Dans IEEE 754, les nombres à virgule flottante de 32 bits sont divisés en trois parties, à savoir le signe, l'exposant et la fraction, totalisant 32 bits
Symbole numérique (signe) : le bit le plus à gauche représente le signe positif et négatif S'il est positif, le signe est 0, sinon c'est 1
1.0001
1.
après avoir supprimé 0001
Donc si 8.5 est exprimé au format 32 bits, cela devrait ressembler à ceci : L'exemple de 8,5 mentionné ci-dessus peut être exprimé sous la forme $2^3 + (cfrac{1}{2})^1$ car 8 et 0,5 se trouvent être des puissances de 2, il n'y aura donc aucun problème de précision.
Mais s'il est 8,9, il n'y a aucun moyen d'ajouter des puissances de 2, il sera donc forcé d'être exprimé comme 1,0001110011 $... fois 2^3$, et il y aura également une erreur d'environ 0,0000003$ si vous. Si vous êtes curieux de connaître le résultat, vous pouvez accéder au site Web du convertisseur à virgule flottante IEEE-754 pour jouer.
Nombres à virgule flottante double précision
Les nombres à virgule flottante simple précision mentionnés précédemment n'utilisent que 32 bits pour les représenter Afin de réduire l'erreur, IEEE 754 définit également comment utiliser 64 bits. pour représenter des nombres à virgule flottante, ce qui équivaut à 32 bits, par rapport au bit, la partie fraction a plus que doublé, passant de 23 bits à 52 bits, la précision sera donc naturellement considérablement améliorée.
Prenons le 8,9 tout à l'heure comme exemple. Bien qu'il puisse être plus précis s'il est exprimé en 64 bits, car 8,9 ne peut pas être complètement écrit comme la somme des puissances de 2, il y aura toujours une erreur en atteignant 16 décimales. places Cependant, avec L'erreur simple précision de 0,0000003 est beaucoup plus petite que
Des situations similaires incluent 1.0
et 0.999...999
en Python sont égales, 123
et 122.999...999
sont également égales, car l'écart entre elles est trop petit pour être placé. Dans la fraction, chaque bit binaire est identique au format binaire.
Étant donné que l'erreur des nombres à virgule flottante est inévitable, nous devons vivre avec. Voici deux méthodes de traitement courantes :
Définir l'erreur maximale autorisée ε (epsilon)
Dans certaines langues, ce qu'on appelle epsilon est fourni pour vous permettre de juger s'il se situe dans la plage autorisée d'erreur en virgule flottante. En Python, la valeur de epsilon est d'environ $2,2e^{-16}$
Vous pouvez ainsi réécrire 0.1 + 0.2 == 0.3
en 0.1 + 0.2 — 0.3 , afin d'éviter que des erreurs en virgule flottante ne causent des problèmes pendant l'opération, et comparer correctement si 0,1 plus 0,2 est égal à 0,3.
Bien sûr, si le système ne le fournit pas, vous pouvez également définir vous-même un epsilon et le régler à environ 2 à la puissance -15
Entièrement en utilisant le système décimal
La raison pour laquelle il existe un L'erreur de virgule flottante est due au fait que pendant le processus de conversion de décimal en binaire, il n'y a aucun moyen de mettre toutes les parties décimales dans la mantisse. Puisqu'il peut y avoir des erreurs dans la conversion, nous ne convertissons tout simplement pas et n'utilisons pas de décimal pour effectuer les calculs. directement.
Il existe un module appelé decimal en Python, et il existe un package similaire en JavaScript. Il peut vous aider à effectuer des calculs en décimal, tout comme vous pouvez calculer 0,1 + 0,2 avec un stylo et du papier sans aucune erreur ni erreur.
Bien que l'utilisation de calculs décimaux puisse éviter complètement les erreurs dans les nombres à virgule flottante, car les calculs décimaux de Decimal sont simulés, les calculs binaires sont toujours utilisés dans le circuit CPU de niveau le plus bas et l'exécution sera plus lente que les calculs à virgule flottante natifs. Les opérations sur virgule sont beaucoup plus lentes, il n'est donc pas recommandé d'utiliser Decimal pour toutes les opérations sur virgule flottante.
Pour plus de connaissances sur la programmation, veuillez visiter : Introduction à la programmation ! !
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!