Le principe des nombres à virgule flottante et l'analyse des causes d'erreurs dans les calculs multiplateformes

Introduisez d'abord la composition et la précision des nombres à virgule flottante, puis introduisez enfin les raisons des erreurs

composition du flotteur

Composition des nombres à virgule flottante : bit de signe, partie exposant, partie mantisse, le bit de signe S occupe 1 bit, l'exposant E occupe 8 bits, la mantisse M occupe 23 bits

méthode de stockage flottant

Tout d'abord, nous savons que la notation scientifique couramment utilisée consiste à convertir tous les nombres en ( ± ) a . b × 1 0 c (±)ab\times10^c( ± ) un . b×1 0La forme de c , où a varie de 1 à 9, un total de 9 entiers, b est tous les chiffres après la virgule et c est l'exposant de 10. L'ordinateur stocke toutes les données binaires, donc les nombres stockés dans float doivent d'abord être convertis en( ± ) a . b × 2 c (±)ab \times 2^c( ± ) un . b×2c , puisque le plus grand nombre en binaire est 1, la notation peut être écrite comme( ± ) 1. b × 2 c (±)1.b \times2^c( ± ) 1.b _×2Sous la forme de c , si float veut stocker des décimales, il n'a besoin que de stocker (±), b et c vont bien. Le stockage de float consiste à diviser 4 octets et 32 ​​bits en 3 parties pour stocker respectivement le signe, la partie décimale et la partie exposant :

  1. Signe (1 bit) : Il est utilisé pour indiquer si le nombre à virgule flottante est positif ou négatif, 0 indique un nombre positif et 1 indique un nombre négatif.
  2. Exposant (8 bits) : partie exposant. C'est-à-dire que le nombre c est mentionné ci-dessus, mais c n'est pas directement stocké ici, pour représenter simultanément les indices positifs et négatifs et leur ordre de grandeur, ce qui est effectivement stocké ici est c+127.
  3. Mantisse (23 bits) : partie de mantisse. C'est le nombre b mentionné ci-dessus.

exemple de stockage flottant

En prenant le nombre 6.5 comme exemple, voyons comment ce nombre est stocké dans la variable flottante :

  1. Regardons d'abord la partie entière. Le reste modulo 2 peut être exprimé par 110 en binaire.
  2. Regardons à nouveau la partie décimale. Multipliez par 2 et arrondissez à un nombre entier pour obtenir la représentation binaire de .1 (si vous ne savez pas comment trouver le binaire d'un nombre décimal, veuillez le rechercher activement).
  3. Assembler ensemble pour obtenir 110,1 puis l'écrire comme une notation scientifique, obtenir 1,101 × 2 2 1,101 \times 2^21.101×22
  4. D'après la formule ci-dessus, nous pouvons savoir que le signe est positif, la mantisse est 101 et l'exposant est 2.
  5. Si le signe est positif, remplissez 0 dans le premier chiffre, l'exposant est 2, plus le décalage de 127 est égal à 129, la représentation binaire est 10000001, remplissez les chiffres 2-9 et remplissez la mantisse restante 101 dans la mantisse.

gamme de flotteur

Après avoir compris les principes ci-dessus, vous pouvez trouver la plage du type flottant, trouver la valeur maximale pouvant être représentée, puis définir le symbole sur 1 et le remplacer par un nombre négatif, qui est la valeur minimale. représentent la plus grande valeur, vous devez avoir la plus grande mantisse et le plus grand exposant.
Ensuite, vous pouvez obtenir la mantisse sous la forme 0,1111111 11111111 11111111 et l'exposant sous la forme 11111111, mais lorsque l'exposant est tout à 1, il a son but particulier, donc l'exposant maximum est 11111110, et l'exposant est soustrait de 127 pour obtenir 127, donc le plus grand nombre est 1,11111111111111111111 × 2 11 1 1 1 1 1 1 1 1 1 1 fois 2^ {127}1.111111111111111111111×2127
, cette valeur est 340282346638528859811704183484516925440, généralement exprimée sous la forme 3.4028235E38, puis la plage de float sort : [-3.4028235E38, 3.4028235E38]

précision du flotteur

La précision des données du type flottant dépend de la mantisse. Je crois que tout le monde le sait, mais j'ai longtemps été confus sur la façon de calculer la précision. Récemment, j'ai progressivement compris dans le processus d'expérimentation continue. Tout d'abord, la mantisse à 23 chiffres n'est pas prise en compte dans le cas de l'exposant. La plage qui peut être représentée est [ 0 , 2 23 − 1 ] [0, 2^{23} −1][ 0 ,2231 ] , en fait, un "1" est implicite devant la mantisse, il devrait donc y avoir un total de 24 chiffres, et la plage qui peut être représentée est[ 0 , 2 24 − 1 ] [0, 2^{ 24} − 1][ 0 ,2241 ] (Parce que le bit implicite est "1" par défaut, le nombre minimum représenté est 1 au lieu de 0, mais 0 n'est pas considéré en premier, et sera spécialement introduit plus tard, ici n'est calculé qu'en fonction de la valeur générale), voir ici nous connaissons ces 24 bits Le plus grand nombre pouvant être représenté est2 24 − 1 2^{24}-12241 , converti en décimal est 16777215, alors [0, 16777215] peut être exprimé avec précision, car ils peuvent tous être écrits sous la forme1. b × 2 c 1.b\times2^c1.b _×2Sous la forme de c , ajustez simplement l'exposant c en conséquence.

Le nombre 16777215 peut s'écrire 1,1111111111111111111 × 2 23 1,1111111 11111111 1111111 \times 2^{23}1.111111111111111111111×223 , afin que ce nombre puisse être représenté avec précision, puis considérons un nombre plus grand 16777216, car il s'agit exactement d'une puissance entière de 2, qui peut représenter 1,0000000000000000000000× 2 24 1,0000000 00000000 00000000 \times 2^{24}1.0000000000000000000000×224 , donc ce nombre peut également être exprimé avec précision. Considérant le plus grand nombre 16777217, si ce nombre est écrit dans la méthode de représentation ci-dessus, il devrait être 1.00000000000000000000001 ∗ 2 24 1.0000000 00000000 00000000 1 * 2^{24}1.00000000000000000000001224 , mais à ce stade, vous constaterez que le nombre de chiffres après la virgule est déjà de 24 chiffres et que l'espace de stockage de 23 chiffres ne peut pas être stocké avec précision.

En voyant cela, j'ai trouvé que 16777216 semble être une limite. Les nombres dépassant ce nombre ne peuvent pas être représentés avec précision. Cela signifie-t-il que tous les nombres supérieurs à 16777216 ne peuvent pas être représentés avec précision ? En fait non, par exemple, le nombre 33554432 peut être exprimé avec précision comme 1.0000000000000000000000 ∗ 2 25 1.0000000 00000000 00000000 * 2^{25}1.0000000000000000000000225 , parlant ici combiné avec la représentation mémoire de float mentionnée ci-dessus, on peut obtenir un nombre supérieur à 16777216 (ne dépassant pas la limite supérieure), tant qu'il peut être exprimé comme l'addition de moins de 24 puissances de n de 2, et entre chaque n Une différence inférieure à 24 peut être représentée avec précision. En d'autres termes, tous les nombres raisonnables supérieurs à 16777216 sont des nombres exacts dans la plage [0, 16777215] en multipliant par2 n 2 ^ n2n obtenu, de même tous les nombres positifs inférieurs à 1 sont également des nombres précis dans la plage [0, 16777215] en multipliant par2 n 2^n2n est obtenu, mais n prend un nombre négatif.

16777216 s'est avéré être une limite, et les nombres entiers inférieurs à ce nombre peuvent être exprimés avec précision, exprimés dans la loi scientifique et technologique est 1,6777216 × 1 0 7 1,6777216 \times 10^{7}1.6777216×1 07. On peut voir d'ici qu'il y a un total de chiffres significatifs 8. Étant donné que le chiffre le plus élevé est au plus 1, il ne peut pas garantir toutes les situations, donc au moins 7 chiffres significatifs peuvent être garantis exacts (il y a à l'origine 8 chiffres, mais le premier chiffre ne peut être que 1 , Par exemple, lorsque 26777216 apparaît, il est inexact, donc seuls 7 chiffres peuvent être garantis), ce qui est souvent appelé la précision des données de type flottant.

virgule flottante

D'après l'analyse ci-dessus, nous savons déjà que float peut représenter des nombres au-delà de la plage de 16777216 sautent, et en même temps, les décimales que float peut représenter sautent également. Ces décimales doivent également pouvoir être écrites comme l'addition de la nième puissance de 2, telle que 0,5, 0,25, 0,125... et la somme de ces nombres, des nombres comme 5,2 ne peuvent pas être stockés avec précision en utilisant le type flottant, et la représentation binaire de 5,2 est 101.0011001100110011001100110011... Les 0011 dernières boucles infiniment, mais float peut stocker jusqu'à 23 chiffres de la mantisse , alors le 5.2 stocké par l'ordinateur doit être 101.001100110011001100110, qui est le nombre 5.19999980926513671875, et l'ordinateur utilise ce nombre le plus proche de 5.2 pour représenter 5.2. La précision de la décimale est cohérente avec l'analyse effectuée à l'instant. Lorsque le 8ème chiffre significatif change, float peut ne pas être en mesure de détecter ce changement.

Causes des erreurs de calcul en virgule flottante sur différentes plates-formes

La précision des nombres à virgule flottante est limitée. Prenons l'exemple de 32 bits :
lors de l'exécution d'opérations à virgule flottante, telles que la multiplication, certaines plates-formes auront une FPU (unité de traitement à virgule flottante) pour le traitement, ce qui peut rendre les résultats de calcul
plus précis. Par exemple : dans le système Under 32 bits, le FPU utilise des registres 80 bits pour les calculs, tandis que le non-FPU utilise SSE. Bien qu'il existe des registres 128 bits, seuls 32 bits d'entre eux sont utilisés (32 bits sont utilisés pour les calculs pendant le processus de calcul), donc dans le calcul Dans le processus, 32 bits seront interceptés pour le calcul, ce qui entraînera des erreurs.

Par conséquent, différentes plates-formes utilisent une logique d'optimisation en virgule flottante différente, ce qui conduira à la même entrée et à une sortie différente.Par exemple, le résultat du calcul de 80838.0f * -2499.0f en C#, le résultat du calcul de linux32 bit est -202014162, et dans Le résultat du calcul de windows32/64 est -202014160, qui est dit être sous Linux 32 bits (Ubuntu 12.04+ gcc 4.6.3), en attente de vérification)

Résumer:

La norme de calcul en virgule flottante IEEE-754 recommande aux implémenteurs standard de fournir des formats de précision évolutifs en virgule flottante. Les processeurs Intel x86 ont des processeurs de calcul en virgule flottante FPU (unité à virgule flottante) qui prennent en charge de telles extensions. D'autres processeurs ne prennent pas nécessairement en charge de telles extensions. ; Sous le système 32 bits, il ne peut pas être représenté par float !

Article de référence :

La précision et la plage de valeurs de float
sont un bogue de nombre à virgule flottante généré par multiplateforme | il y a des résultats inattendus

Je suppose que tu aimes

Origine blog.csdn.net/qq_41841073/article/details/127057494
conseillé
Classement