Vous avez un problème avec les mathématiques en virgule flottante ?
P粉827121558
P粉827121558 2023-10-11 15:44:28
0
2
499

Considérez le code suivant :

0.1 + 0.2 == 0.3  ->  false
0.1 + 0.2         ->  0.30000000000000004

Pourquoi ces inexactitudes se produisent-elles ?

P粉827121558
P粉827121558

répondre à tous(2)
P粉818561682

Point de vue du concepteur de matériel

Je pense que je devrais ajouter le point de vue d'un concepteur de matériel, puisque je conçois et construis du matériel à virgule flottante. Connaître la source 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 inférieure à la moitié d'une unité dans le dernier bit. Par conséquent, de nombreux matériels s'arrêteront à une précision qui ne nécessite qu'une erreur inférieure à une unité sur le dernier bit d'une seule opération , ce qui est particulièrement problématique dans la division en virgule flottante. Ce qui constitue une opération unique dépend du nombre d’opérandes requis pour cette unité. Pour la plupart, c'est deux, mais certaines unités nécessitent 3 opérandes ou plus. Par conséquent, il n’y a aucune garantie que des opérations répétées entraîneront l’erreur souhaitée, car les erreurs s’accumulent 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, le mode standardisé IEEE-754 est décrit ci-dessous, qui constitue le mode de fonctionnement typique.

Dans la norme IEEE-754, les concepteurs de matériel sont autorisés à utiliser n'importe quelle valeur d'erreur/epsilon à condition qu'elle soit inférieure à la moitié d'une unité du dernier chiffre, et le résultat ne doit être que inférieur à la moitié de une unité à utiliser immédiatement. La dernière position de l'opération. Ceci explique pourquoi les erreurs s'accumulent lorsque les opérations sont répétées. Pour la double précision IEEE-754, il s'agit du bit 54 car le bit 53 est utilisé pour représenter la partie numérique (normalisée) du nombre à virgule flottante, également connue sous le nom de mantisse (par exemple 5.3 en 5.3e5). Les sections suivantes expliquent 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 des erreurs de division en virgule flottante est l'algorithme de division utilisé pour calculer le quotient. La plupart des systèmes informatiques utilisent la multiplication inverse pour calculer la division, principalement

bits (plus quelques bits facultatifs). Z=X/YZ = X * (1/Y)。除法是迭代计算的,即每个周期计算商的一些位,直到达到所需的精度,对于 IEEE-754 来说,精度是最后一位误差小于一个单位的任何值。 Y(1/Y)的倒数表在慢除法中被称为商选择表(QST),商选择表的大小(以位为单位)通常是基数的宽度,或者是基数的位数。每次迭代中计算的商,加上一些保护位。对于 IEEE-754 标准,双精度(64 位),它是除法器基数的大小,加上一些保护位 k,其中 k>=2。例如,一次计算 2 位商(基数 4)的除法器的典型商选择表将是 2+2= 4

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 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 essayer de produire la plus petite erreur possible ; Quoi qu’il en soit, toutes les réciproques sont des approximations des réciproques réelles et introduiront un élément d’erreur. La division lente et la division rapide calculent le quotient de manière itérative, c'est-à-dire que chaque étape calcule un nombre de chiffres dans le quotient puis soustrait le résultat du dividende. Le diviseur répète ces étapes jusqu'à ce que l'erreur soit inférieure à une demi-unité en dernier lieu. . Les méthodes de division lente calculent le quotient d'un nombre fixe de chiffres à chaque étape et sont généralement moins coûteuses à construire, tandis que les méthodes de division rapide calculent un nombre variable de chiffres à chaque étape et sont généralement plus coûteuses à construire. La partie la plus importante concernant la division est que la plupart d'entre elles reposent sur des multiplications répétées de l'approximation de l'inverse, il est donc facile de faire des erreurs.

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

Une autre raison des erreurs d'arrondi dans toutes les opérations réside dans les différents modes de troncature de la réponse finale autorisés par IEEE-754. Il y a tronqué, arrondi vers zéro, arrondi au plus proche (par défaut), arrondi vers le bas, arrondi vers le haut. Pour une seule opération, toutes les méthodes introduisent un élément d’erreur inférieur à une unité à la fin. La troncature augmente également de manière cumulative l'erreur finale au fil du temps et avec des opérations répétées. Cette erreur de troncature est particulièrement problématique lorsque l'exponentiation implique une forme de multiplication répétée.

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

Étant donné que le matériel qui effectue les calculs en virgule flottante n'a besoin que de produire un résultat avec une erreur inférieure à la moitié sur le dernier bit en une seule opération, si vous n'y faites pas attention, l'erreur augmentera avec les opérations répétées. C'est pourquoi, dans les calculs qui nécessitent des erreurs limitées, les mathématiciens utilisent des méthodes telles que l'arrondi au Arithmétique d'intervalle est combinée avec une variante du Mode d'arrondi IEEE 754 pour prédire les erreurs d'arrondi et les corriger. L'arrondi au chiffre pair le plus proche (dernier chiffre) 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 arrondit au nombre pair a> le plus proche du dernier chiffre, garantissant ainsi que l'erreur du dernier chiffre en une opération est inférieure à la moitié. La troncature, l'arrondi vers le haut et l'arrondi vers le bas seuls peuvent entraîner des erreurs supérieures à la moitié du dernier chiffre mais inférieures à une unité du dernier chiffre. Ces modes ne sont donc pas recommandés, sauf pour l'arithmétique des intervalles.

6. Résumé

En bref, la cause première des erreurs dans les opérations en virgule flottante est une combinaison de troncature matérielle et de troncature réciproque lors de la division. Étant donné que la norme IEEE-754 exige uniquement que l'erreur dans le dernier bit d'une opération unique soit inférieure à la moitié, les erreurs en virgule flottante provenant d'opérations répétées s'accumuleront à moins qu'elles ne soient corrigées.

P粉605385621

Binaire Point flottantLes mathématiques 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 des nombres entiers multipliés par des puissances de 2 ; les nombres rationnels dont les dénominateurs ne sont pas des puissances de 2 (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 rationnels0.1,即1/10 peuvent s'écrire exactement comme

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

Les constantes 0.2 et 0.3 dans le programme seront également des approximations de leurs vraies valeurs. Il se trouve que le double le plus proche de 0.2 est plus grand que le nombre rationnel 0.2, mais le plus proche de double code>0.3 Inférieur à un nombre rationnel 0.3. La somme de 0.20.3也将是其真实值的近似值。碰巧,最接近 0.2double 大于有理数 0.2,但最接近 double code>0.3 小于有理数 0.30.10.2 的总和最终大于有理数 0.3 et 0,2 finit par être supérieure au nombre rationnel 0,3 et est donc incompatible avec la constante du code.

Un traitement assez complet des problèmes d'arithmétique à virgule flottante est Tout informaticien devrait connaître l'arithmétique à virgule flottante. Pour une explication plus compréhensible, voir floating-point-gui.de.

Les vieux nombres décimaux (base 10) ont le même problème, c'est pourquoi un nombre comme 1/3 finit par être 0,333333333...

Vous venez de tomber sur un nombre (3/10) qui est facilement représenté en décimal, mais pas en binaire. Cela va aussi dans les deux sens (dans une certaine mesure) : 1/16 est un nombre laid en décimal (0,0625), mais en binaire, il ressemble au 10 000e décimal (0,0001)** - si nous sommes en retard, nous avons un l'habitude d'utiliser un système numérique de base 2 dans notre vie quotidienne, et vous verrez même le nombre et comprendrez instinctivement que vous pouvez atteindre ce nombre en divisant par deux quelque chose, et en le divisant par deux encore, encore et encore.

Bien sûr, ce n'est pas exactement ainsi que les nombres à virgule flottante sont stockés en mémoire (ils utilisent la notation scientifique). Cependant, cela illustre que des erreurs de précision binaires à virgule flottante ont tendance à se produire parce que les nombres du « monde réel » qui nous intéressent habituellement sont généralement des puissances de dix – mais c'est uniquement parce que nous utilisons le système de nombres décimaux à l'époque – aujourd'hui. C'est pourquoi nous disons 71 % au lieu de « 5 sur 7 » (71 % est une approximation car 5/7 ne peut être représenté exactement par aucun nombre décimal).

Donc non : les nombres binaires à virgule flottante ne sont pas cassés, ils sont simplement imparfaits comme tous les autres systèmes numériques basés sur N :)

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

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

Ne pas ne pas faire if (x == y) { ... }

Exécutez plutôt if (abs(x - y) .

Lequel abs 是绝对值。 myToleranceValue doit être choisi en fonction de votre application spécifique - cela a beaucoup à voir avec la "marge de manœuvre" que vous êtes prêt à accorder, et quel sera probablement le plus grand nombre que vous comparez (en raison de problèmes de perte de précision) . Notez les constantes de style "epsilon" dans la langue de votre choix. Celles-ci peuvent être utilisées comme valeurs de tolérance, mais leur efficacité dépend de la taille (taille) des nombres avec lesquels vous travaillez, car 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