[PYTHON] Pourquoi le nombre à virgule flottante de 0,1 est-il supérieur à 0,1, mais lorsqu'il est ajouté 10 fois, il est inférieur à 1,0 [Partie 2]

Partie 1

Ceci est une suite de cet article.

Pourquoi le nombre à virgule flottante de 0,1 est-il supérieur à 0,1, mais il est inférieur à 1,0 lorsqu'il est ajouté 10 fois [Partie 1]

(Copie de la première partie) Lorsque 0,1 est représenté par un nombre à virgule flottante

Le signe, l'exposant et le nombre incorrect lorsque «0,1» est exprimé en nombre à virgule flottante sont les suivants.

Code= 0
indice= 01111111011
mantisse= 1001100110011001100110011001100110011001100110011010

L'exposant est «1019» en décimal. L'exposant à virgule flottante a "1023" ajouté, donc soustraire cela donne "-4".

(Copie de la première partie) Combien est ajouté au résultat lorsque 0,1 est ajouté

Le tableau ci-dessous montre les résultats du calcul lorsque `` 0,1 '' est ajouté aux lignes impaires à l'exclusion de l'en-tête, et les différences entre les lignes paires.

Valeur attendue Résultat du calcul / différence
0.1 0.1000000000000000055511151231257827021181583404541015625
0.1000000000000000055511151231257827021181583404541015625
0.2 0.200000000000000011102230246251565404236316680908203125
0.100000000000000033306690738754696212708950042724609375
0.3 0.3000000000000000444089209850062616169452667236328125
0.09999999999999997779553950749686919152736663818359375
0.4 0.40000000000000002220446049250313080847263336181640625
0.09999999999999997779553950749686919152736663818359375
0.5 0.5
0.09999999999999997779553950749686919152736663818359375
0.6 0.59999999999999997779553950749686919152736663818359375
0.09999999999999997779553950749686919152736663818359375
0.7 0.6999999999999999555910790149937383830547332763671875
0.09999999999999997779553950749686919152736663818359375
0.8 0.79999999999999993338661852249060757458209991455078125
0.09999999999999997779553950749686919152736663818359375
0.9 0.899999999999999911182158029987476766109466552734375
0.09999999999999997779553950749686919152736663818359375
1.0 0.99999999999999988897769753748434595763683319091796875

(Copie de la première partie) Procédure d'ajout de nombres à virgule flottante

L'addition de nombres à virgule flottante positifs est effectuée par la procédure suivante.

① Faites correspondre l'index le plus petit avec l'index le plus grand (2) Ajustez en réduisant le nombre incorrect à mesure que l'exposant augmente. ③ Ajoutez les numéros incorrects ④ En cas de report, ajoutez 1 à l'exposant et réduisez le pseudonyme en conséquence. ⑤ Arrondissez les chiffres débordants du nombre incorrect (même arrondi)

(Copie de la première partie) Poutre de protection et embout collant

Les chiffres de garde sont la zone pour stocker les chiffres qui débordent. Sticky bit est une valeur booléenne qui indique si le nombre sous le chiffre de protection contient un nombre supérieur ou égal à 1.

Dans la première partie, il a été mentionné qu'un seul chiffre de protection suffit pour ajouter des nombres positifs, mais que deux chiffres sont nécessaires lors du développement en nombres négatifs. Ce qui suit utilise deux chiffres de protection et un embout collant. Les deux chiffres (2 bits) du chiffre de protection sont appelés Guard bit et Round bit à partir du haut.

Processus de calcul lorsque 0,1 est ajouté 10 fois

Vérifiez le processus de calcul lors de l'ajout de "0,1" étape par étape.

Expression utilisée cette fois

Cette fois, je vais vous expliquer en utilisant la figure suivante.

f_legend.png

nombre Nom de colonne La description
Approximatif Il décrit en gros le type de calcul effectué.
indice(Nombre décimal) 浮動小数点数で表されたindiceを、10進数に変換し、1023を引いたものです。
Déplacer vers le haut À la suite de l'ajout, les chiffres peuvent être reportés, de sorte qu'une grande partie de la zone est sécurisée.
Partie entière 浮動小数点形式ではPartie entièreは常に1est.
0 à 52 C'est un nombre incorrect. Comme il est difficile de voir si les 52 chiffres sont affichés, seuls les 8 chiffres supérieurs et les 8 chiffres inférieurs sont affichés.
Garde rond collant La poutre de protection et le mors collant décrits ci-dessus.

0,1 + 0,1 processus de calcul

Vérifiez le processus de calcul de `` 0,1 + 0,1 ''. f0_1_1.png

① Faites correspondre l'index le plus petit avec l'index le plus grand (2) Ajustez en réduisant le nombre incorrect à mesure que l'exposant augmente. Puisque les index sont les mêmes, rien n'est fait.

③ Ajoutez les numéros incorrects C'est le résultat de l'ajout f0_1_2.png

④ En cas de report, ajoutez 1 à l'exposant et réduisez le pseudonyme en conséquence. Puisqu'il y a une retenue, ajoutez «1» à l'exposant et divisez le nombre incorrect par «2». Puisqu'il s'agit d'un nombre binaire, la division par 2 décale un chiffre vers la droite (décalage de bits). f0_1_3.png

⑤ Arrondissez les chiffres débordants du nombre incorrect (même arrondi) Le seul bit qui déborde est «0», alors tronquez-le. f0_1_4.png

Au dessus de,

indice= -3 (Nombre décimal)
mantisse= 1001100110011001100110011001100110011001100110011010 (Nombre binaire)

A été obtenu. Si vous le convertissez en nombre décimal,

0.200000000000000011102230246251565404236316680908203125

est.

Processus de calcul de 0,2 (somme cumulée) + 0,1

Ajoutez `` 0,1 '' à la valeur obtenue ci-dessus. f0_2_1.png

① Faites correspondre l'index le plus petit avec l'index le plus grand (2) Ajustez en réduisant le nombre incorrect à mesure que l'exposant augmente. Puisque l'exposant de «0,2» est «1» plus grand, ajoutez «1» à l'exposant de «0,1» et décalez le nombre incorrect vers la droite de «1». f0_2_2.png

③ Ajoutez les numéros incorrects C'est le résultat de l'addition. f0_2_3.png

④ En cas de report, ajoutez 1 à l'exposant et réduisez le pseudonyme en conséquence. Puisqu'il y a une retenue, ajoutez «1» à l'exposant et décalez le nombre incorrect vers la droite «1». f0_2_4.png

⑤ Arrondissez les chiffres débordants du nombre incorrect (même arrondi) Le chiffre qui déborde est "10", qui est exactement la moitié, donc arrondissez-le dans le sens pair. Cette fois, le bit le moins significatif du nombre incorrect est "1", alors arrondissez-le. f0_2_5.png

Au dessus de,

indice= -2 (Nombre décimal)
mantisse= 11001100110011001100110011001100110011001100110100 (Nombre binaire)

A été obtenu. Si vous le convertissez en nombre décimal,

0.3000000000000000444089209850062616169452667236328125

est.

Dans 0,2 (somme cumulée) + 0,1 '', 0,1 '' est à l'origine plus grand que 0,1 '' en nombres à virgule flottante, et le résultat ajouté est arrondi davantage, donc imprimer '' Vous verrez des résultats qui ne sont pas ceux que vous attendiez lorsque vous l'avez fait.

print(0.1 + 0.1 + 0.1)
# => 0.30000000000000004

Processus de calcul de 0,3 (somme cumulée) + 0,1

Ajoutez `` 0,1 '' à la valeur obtenue ci-dessus. f0_3_1.png

① Faites correspondre l'index le plus petit avec l'index le plus grand (2) Ajustez en réduisant le nombre incorrect à mesure que l'exposant augmente. Puisque "0,3" a un exposant plus grand, "2" est ajouté à l'exposant de "0,1" et le nombre incorrect est décalé vers la droite de "2". f0_3_2.png

③ Ajoutez les numéros incorrects C'est le résultat de l'addition. f0_3_3.png

④ En cas de report, ajoutez 1 à l'exposant et réduisez le pseudonyme en conséquence. Pas de report, alors ne fais rien

⑤ Arrondissez les chiffres débordants du nombre incorrect (même arrondi) Le chiffre qui déborde est "10", qui est exactement la moitié, donc arrondissez-le dans le sens pair. Cette fois, le bit le moins significatif du nombre incorrect est 0, il est donc tronqué. f0_3_4.png

Au dessus de,

indice= -2 (Nombre décimal)
mantisse= 1001100110011001100110011001100110011001100110011010 (Nombre binaire)

A été obtenu. Si vous le convertissez en nombre décimal,

0.40000000000000002220446049250313080847263336181640625

est.

Processus de calcul de 0,4 (somme cumulée) + 0,1

Ajoutez «0,1» à la valeur obtenue ci-dessus. f0_4_1.png

① Faites correspondre l'index le plus petit avec l'index le plus grand (2) Ajustez en réduisant le nombre incorrect à mesure que l'exposant augmente. Puisque l'exposant de «0,4» est «2» plus grand, ajoutez «2» à l'exposant de «0,1» et décalez le nombre incorrect vers la droite de «2». f0_4_2.png

③ Ajoutez les numéros incorrects C'est le résultat de l'addition. Toutes les valeurs de la partie formelle sont désormais «0». f0_4_3.png

④ En cas de report, ajoutez 1 à l'exposant et réduisez le pseudonyme en conséquence. Puisqu'il y a une retenue, ajoutez «1» à l'exposant et décalez le nombre incorrect vers la droite de «1». f0_4_4.png

⑤ Arrondissez les chiffres débordants du nombre incorrect (même arrondi) Le chiffre qui déborde est «010», il sera donc tronqué. f0_4_5.png

Au dessus de,

indice= -1 (Nombre décimal)
mantisse= 0000000000000000000000000000000000000000000000000000 (Nombre binaire)

A été obtenu. Convertir cela en un nombre décimal,

0.5

est. C'était une coïncidence qu'il soit devenu parfait.

Processus de calcul de 0,5 (somme cumulée) + 0,1

Ajoutez «0,1» à la valeur obtenue ci-dessus. f0_5_1.png

① Faites correspondre l'index le plus petit avec l'index le plus grand (2) Ajustez en réduisant le nombre incorrect à mesure que l'exposant augmente. Puisque l'exposant de «0,5» est «3» plus grand, ajoutez «3» à l'exposant de «0,1» et décalez le nombre incorrect vers la droite de «3». f0_5_2.png

③ Ajoutez les numéros incorrects C'est le résultat de l'addition. f0_5_3.png

④ En cas de report, ajoutez 1 à l'exposant et réduisez le pseudonyme en conséquence. Pas de report, alors ne fais rien

⑤ Arrondissez les chiffres débordants du nombre incorrect (même arrondi) Le chiffre qui déborde est «010», il sera donc tronqué. f0_5_4.png

Au dessus de,

indice= -1 (Nombre décimal)
mantisse= 11001100110011001100110011001100110011001100110011 (Nombre binaire)

A été obtenu. Convertir cela en un nombre décimal,

0.59999999999999997779553950749686919152736663818359375

est.

Processus de calcul de 0,6 (somme cumulée) + 0,1, 0,7 (somme cumulée) + 0,1, 0,8 (somme cumulée) + 0,1

Puisque «0,6» à «0,8» sont presque identiques à «0,5 (somme cumulée) + 0,1», ils sont omis. Des valeurs inférieures à «1» ont été ajoutées dans cette plage en raison de la troncature des valeurs.

Processus de calcul de 0,9 (somme cumulée) + 0,1

C'est presque la même chose que «0,5 (somme cumulée) + 0,1», mais voyons à quoi ressemble le résultat. f0_9_1.png

① Faites correspondre l'index le plus petit avec l'index le plus grand (2) Ajustez en réduisant le nombre incorrect à mesure que l'exposant augmente. Puisque l'exposant de «0,9» est «3» plus grand, ajoutez «3» à l'exposant de «0,1» et décalez le nombre incorrect vers la droite de «3». f0_9_2.png

③ Ajoutez les numéros incorrects C'est le résultat de l'addition. f0_9_3.png

④ En cas de report, ajoutez 1 à l'exposant et réduisez le pseudonyme en conséquence. Pas de report, alors ne fais rien

⑤ Arrondissez les chiffres débordants du nombre incorrect (même arrondi) Le chiffre qui déborde est «010», il sera donc tronqué. f0_9_4.png

Au dessus de,

indice= -1 (Nombre décimal)
mantisse= 1111111111111111111111111111111111111111111111111111 (Nombre binaire)

A été obtenu. Convertir cela en un nombre décimal,

0.99999999999999988897769753748434595763683319091796875

est.

Jusqu'à présent, nous avons confirmé l'opération lorsque `` 0,1 '' est ajouté 10 fois.

Résumé

La réponse est pourquoi, lorsque «0,1» est un nombre à virgule flottante, il est légèrement supérieur à «0,1», mais lorsqu'il est ajouté 10 fois, il est inférieur à «1,0». En effet, lors de l'ajout de deux nombres à virgule flottante, nous avons arrondi les nombres qui ne pouvaient pas tenir dans le nombre incorrect.

Matériel de référence

Outils utilisés, etc.

Recommended Posts

Pourquoi le nombre à virgule flottante de 0,1 est-il supérieur à 0,1, mais lorsqu'il est ajouté 10 fois, il est inférieur à 1,0 [Partie 1]
Pourquoi le nombre à virgule flottante de 0,1 est-il supérieur à 0,1, mais lorsqu'il est ajouté 10 fois, il est inférieur à 1,0 [Partie 2]
Pourquoi 0,1 est-il affiché comme 0,1 lors de l'impression alors que 0,1 ne peut pas être représenté avec précision par un nombre à virgule flottante?
Vérifions la chaîne d'octets en mémoire du nombre flottant flottant en Python
Il semble que la version de pyflakes ne soit pas la dernière lorsque flake8 est installé
L'apprentissage en profondeur! L'histoire des données elles-mêmes qui sont lues lorsqu'elles ne suivent pas après la reconnaissance des nombres manuscrits