Y a-t-il un problème avec l'arithmétique à virgule flottante ?
P粉330232096
P粉330232096 2023-08-21 15:24:30
0
2
553
<p>Considérez le code suivant : </p> <pre class="brush:js;toolbar:false;">0,1 + 0,2 == 0,3 -> ≪/pré> <pre class="brush:js;toolbar:false;">0,1 + 0,2 -> ≪/pré> <p>Pourquoi ces inexactitudes se produisent-elles ? </p>
P粉330232096
P粉330232096

répondre à tous(2)
P粉041856955

Point de vue du concepteur de matériel

J'ai pensé ajouter une certaine perspective du point de vue d'un concepteur de matériel, puisque je conçois et construis du matériel à virgule flottante. Connaître l'origine de l'erreur peut aider à comprendre ce qui se passe dans le logiciel et, en fin de compte, j'espère que cela aidera à expliquer pourquoi les erreurs en virgule flottante se produisent et semblent s'accumuler au fil du temps.

1. Aperçu

D'un point de vue technique, la plupart des opérations en virgule flottante comporteront des erreurs, car le matériel effectuant les calculs en virgule flottante n'a besoin que d'une erreur d'une unité inférieure à la moitié du dernier bit. Par conséquent, la plupart des matériels s'arrêteront à une précision qui ne nécessite que de produire moins de la moitié de l'erreur du dernier bit en une seule opération, ce qui est particulièrement délicat dans la division en virgule flottante. Ce qui constitue une opération unique dépend du nombre d'opérandes acceptés par l'unité. Pour la plupart des unités, c'est deux, mais certaines unités acceptent 3 opérandes ou plus. Par conséquent, il n’y a aucune garantie que des opérations répétées produiront des erreurs idéales, car ces erreurs s’accumuleront au fil du temps.

2. Norme

La plupart des processeurs suivent la norme IEEE-754, mais certains utilisent des normes dénormalisées ou différentes. Par exemple, il existe un mode de dénormalisation dans IEEE-754 qui permet de représenter de très petits nombres à virgule flottante au détriment de la précision. Cependant, ce qui suit décrit le mode normalisé de IEEE-754, qui est le mode de fonctionnement typique.

Dans la norme IEEE-754, les concepteurs de matériel peuvent choisir n'importe quelle valeur d'erreur/epsilon à condition qu'elle soit inférieure à la moitié de l'unité du dernier bit, et le résultat ne doit être que inférieur à la moitié de l'unité du dernier bit en un. opération. Cela explique pourquoi les erreurs s'accumulent au fil des opérations répétées. Pour la double précision IEEE-754, il s'agit du bit 54 car 53 bits sont utilisés pour représenter la partie numérique (partie normalisée) du nombre à virgule flottante, également appelée mantisse (par exemple 5,3 en 5.3e5). Les prochaines sections examineront plus en détail les causes des erreurs matérielles dans diverses opérations en virgule flottante.

3. Causes des erreurs de division et d'arrondi

La principale cause d'erreur dans la division en virgule flottante est l'algorithme de division utilisé pour calculer le quotient. La plupart des systèmes informatiques utilisent l'inverse de la multiplication pour calculer la division, principalement dans le bit Z=X/YZ = X * (1/Y)中。除法是迭代计算的,即每个周期计算一些商的位数,直到达到所需的精度,对于IEEE-754来说,这是任何误差小于最后一位的一半以下的内容。Y的倒数表(1/Y)称为慢除法中的商选择表(QST),商选择表的位数通常是基数的宽度,或者每次迭代计算的商的位数加上几个保护位。对于IEEE-754标准的双精度(64位),它将是除法器的基数大小加上几个保护位k,其中k>=2。因此,例如,一个每次计算2位商(基数为4)的典型商选择表将是2+2= 4 (plus quelques bits facultatifs).

3.1 Erreur d'arrondi de division : approximation de l'inverse

Les réciproques dans le tableau de sélection des quotients dépendent de la méthode de division : division lente (comme la division SRT) ou division rapide (comme la division Goldschmidt) ; chaque entrée est modifiée selon l'algorithme de division pour minimiser l'erreur. Quoi qu'il en soit, toutes les réciproques sont des approximations des réciproques réelles et introduisent une certaine quantité d'erreur. Les méthodes de division lente et de division rapide calculent le quotient de manière itérative, c'est-à-dire que chaque étape calcule un certain nombre de chiffres du quotient, puis soustrait le résultat du dividende, et le diviseur répète ces étapes jusqu'à ce que l'erreur soit inférieure à la moitié de la dernière. chiffre. Les méthodes de division lente calculent un nombre fixe de chiffres du quotient à chaque étape et sont généralement moins chères, tandis que les méthodes de division rapide calculent un nombre variable de chiffres du quotient à chaque étape et sont généralement plus coûteuses. La partie la plus importante des méthodes de division est que la plupart d'entre elles reposent sur une multiplication répétée par se rapprochant de l'inverse de , elles sont donc sujettes aux erreurs.

4. Erreurs d'arrondi dans d'autres opérations : troncature

Une autre cause d'erreurs d'arrondi dans toutes les opérations est les différents modes de troncature autorisés par IEEE-754. Il y a tronqué, arrondi vers zéro, arrondi au plus proche (par défaut) , arrondi vers le bas et arrondi vers le haut. Toutes les méthodes introduisent une erreur inférieure à la moitié de l’unité du dernier bit pour une seule opération. Au fil du temps et des opérations répétées, la troncature s'accumule également dans l'erreur qui en résulte. Cette erreur de troncature est particulièrement gênante dans les opérations exponentielles impliquant une forme de multiplication répétée.

5. Répétez l'opération

Étant donné que le matériel effectuant des calculs en virgule flottante n'a besoin que de produire des résultats avec moins de la moitié de l'erreur du dernier bit d'une unité en une seule opération, si elle n'est pas observée, l'erreur augmentera à mesure que l'opération est répétée. C'est pourquoi, dans les calculs qui nécessitent des erreurs limitées, les mathématiciens utilisent des méthodes telles que l'utilisation des chiffres pairs arrondis les plus proches de l'IEEE-754, car les erreurs sont plus susceptibles de s'annuler avec le temps, et l'arithmétique des intervalles Incorpore des variantes de IEEE 754. modes d'arrondi pour prédire les erreurs d'arrondi et les corriger. L'arrondi au chiffre pair le plus proche (au dernier bit) est le mode d'arrondi par défaut pour IEEE-754 en raison de l'erreur relative plus faible par rapport aux autres modes d'arrondi.

Veuillez noter que le mode d'arrondi par défaut, arrondi au chiffre pair le plus proche, garantit une opération avec une erreur inférieure à la demi-unité du dernier chiffre. Utiliser uniquement la troncature, l'arrondi vers le haut et vers le bas peut entraîner une erreur supérieure à la moitié d'une unité du dernier chiffre mais inférieure à une unité du dernier chiffre, donc à moins que vous ne calculiez sur un intervalle

P粉041881924

Les opérations

Binaireà virgule flottante sont comme ça. Dans la plupart des langages de programmation, il est basé sur la norme IEEE 754. Le nœud du problème est que les nombres sont représentés dans ce format comme un nombre entier multiplié par une puissance de deux ; les nombres rationnels dont les dénominateurs ne sont pas des puissances de deux (comme 0.1,即1/10) ne peuvent pas être représentés exactement.

Pour le standard binary64格式中的0.1, sa représentation peut s'écrire exactement comme

En revanche, les nombres rationnels 0.1,即1/10 peuvent s'écrire exactement comme

  • 0.1 (décimal), ou
  • 0x1.99999999999999...p-4(类似于C99十六进制浮点表示法,其中... représente une séquence infinie de 9).

Les constantes 0.2 et 0.3 de votre programme seront également des approximations de leurs vraies valeurs. Exactement 0,2 le double le plus proche est supérieur au nombre rationnel 0,2, mais le double le plus proche est inférieur au rationnel numéro 0.3. La somme de 0.20.3也将是它们真实值的近似值。恰好0.2最接近的double大于有理数0.2,但最接近的double小于有理数0.30.10.2的和最终大于有理数0.3 et 0,2 finit par être supérieure au nombre rationnel 0,3, elle est donc incompatible avec la constante du code.

Un traitement assez complet de l'arithmétique à virgule flottante est "Ce que les informaticiens devraient savoir sur l'arithmétique à virgule flottante". Pour une explication plus compréhensible, voir floating-point-gui.de.

Le même problème existe avec les nombres décimaux réguliers (base 10), c'est pourquoi un nombre comme 1/3 finit par 0,333333333...

Vous venez de rencontrer un nombre (3/10) qui est facilement représenté dans le système décimal, mais ne peut pas être représenté dans le système binaire. La situation est également inversée (d'une certaine manière) : 1/16 est un nombre laid en décimal (0,0625), mais il semble joli en binaire comme 1/10000 en décimal (0,0001)** - Si nous avions l'habitude d'utiliser le nombre binaire système dans notre vie quotidienne, vous regarderiez même ce nombre et comprendriez instinctivement que vous pourriez l'obtenir en le pliant constamment en deux.

Bien sûr, ce n’est pas exactement ainsi que les nombres à virgule flottante sont stockés en mémoire (ils utilisent une forme de notation scientifique). Cela illustre cependant que des erreurs de précision binaires à virgule flottante ont tendance à survenir parce que les nombres du « monde réel » qui nous intéressent habituellement ont tendance à être des puissances de dix – mais uniquement parce que nous utilisons quotidiennement un système de nombres décimaux. C'est pourquoi on dit 71 % au lieu de « 5 sur 7 » (71 % est une approximation, puisqu'aucun nombre décimal ne peut représenter exactement 5/7).

Donc non, les nombres binaires à virgule flottante ne sont pas brisés, ils sont simplement imparfaits comme tout autre système numérique de base N :)

En pratique, ce problème de précision signifie que vous devez utiliser une fonction d'arrondi pour arrondir le nombre à virgule flottante au nombre de décimales qui vous intéresse avant de l'afficher.

Il faut également remplacer le test d'égalité par une comparaison qui autorise une certaine tolérance, ce qui signifie :

Ne pas utiliserif (x == y) { ... }

Utilisez plutôt if (abs(x - y) < myToleranceValue) { ... }.

abs是绝对值函数。需要根据您的特定应用选择myToleranceValue - Cela a beaucoup à voir avec la « marge de manœuvre » que vous êtes prêt à accorder et le nombre maximum auquel vous comparez (en raison de problèmes de perte de précision). Veuillez noter les constantes de style "epsilon" dans la langue de votre choix. Ces constantes peuvent être utilisées comme valeurs de tolérance, mais leur efficacité dépend de la taille des nombres avec lesquels vous travaillez (puisque les calculs sur de grands nombres peuvent dépasser le seuil epsilon).

Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal