Lorsque la conversion d'Integer en Single peut perdre en précision

27

Je lisais un article de Microsoft concernant l'élargissement des conversions et l'option Strict On lorsque je suis arrivé à la partie

Les conversions suivantes peuvent perdre en précision:

  • Entier à célibataire
  • Long à simple ou double
  • Décimal en simple ou double

Cependant, ces conversions ne perdent ni informations ni ampleur.

.. mais selon un autre article concernant les types de données ,

  • Le type entier peut stocker de -2.147.483.648 à 2.147.483.647 et

  • Un type unique peut stocker à partir de

    • 1,401298E-45 à 3,4028235E + 38 pour les nombres positifs,
    • et -3,4028235E + 38 à - 1,401298E-45 pour les nombres négatifs

.. donc Single peut stocker beaucoup plus de nombres que Integer. Je ne pouvais pas comprendre dans quelle situation une telle conversion d'Integer en Single peut perdre en précision. Quelqu'un pourrait-il expliquer, s'il vous plaît?

Vinicius V
la source

Réponses:

87

Single peut stocker beaucoup plus de nombres qu'Integer

Non, ça ne peut pas. Les deux Singleet Integersont 32 bits, ce qui signifie que les deux peuvent stocker exactement le même nombre de nombres, à savoir 2 32 = 4294967296 nombres distincts.

Étant donné que la plage de Singleest clairement plus grande que cela, il est immédiatement évident (en raison du principe du pigeonnier ) qu'il ne peut pas représenter tous les nombres de cette plage.

Et puisque la plage de Integerest exactement de la même taille que le nombre maximal de nombres que les deux Integeret Singlepeuvent représenter, mais Singlepeut également représenter des nombres en dehors de cette plage, il est clair qu'elle ne peut pas représenter tous les nombres à l'intérieur de la plage de Integer.

Si certains nombres Integerne peuvent pas être représentés dans Single, la conversion de Integerà Single doit être capable de perdre des informations.

Jörg W Mittag
la source
3
+1 pour cette excellente explication de la raison pour laquelle cela doit être le cas, même si la question était en fait quand ("dans quelle situation") cela se produit ...
doubleYou
21
@doubleYou: 4261412864 des 4294967296 Integers (99,2%) ne peuvent pas être représentés comme Single, donc "quand" est "à peu près toujours".
Jörg W Mittag
2
Si vous voulez être plus précis, Singlene peut représenter que 4 278 178 909 nombres différents. Une Singlevaleur représente un nombre si et seulement si l'exposant stocké n'est pas 255, ce qui signifie qu'il y a 255 * 2 ^ 24 Singles qui représentent des nombres. Parmi ceux-ci, deux d'entre eux représentent le même nombre (à savoir zéro), et les autres représentent tous des nombres différents.
Tanner Swett
10
en.wikipedia.org/wiki/Single-precision_floating-point_format explique bien les limitations pour IEEE754 binary32. Les entiers dans [-16777216,16777216](2 ^ 24 = la largeur de la signification) peuvent être représentés exactement. Les plus grands nombres sont arrondis au multiple le plus proche de 2, 4, 8, ... selon leur taille.
Peter Cordes
14
«Ce qui signifie que les deux peuvent stocker exactement le même nombre de chiffres» - Cela ne signifie pas cela. Cela signifierait seulement que si les deux types ont exactement le même nombre de façons de stocker chaque numéro. Et ce n'est pas le cas; par exemple, Singlea deux façons de stocker zéro. SinglePeut donc en fait représenter moins de nombres distincts que Integer.
Konrad Rudolph
28

Les types à virgule flottante (tels que simple et double) sont représentés en mémoire par un signe, une mantisse et un exposant. Considérez-le comme une notation scientifique:

Sign*Mantissa*Base^Exponent

Ils - comme vous pouvez vous y attendre - utilisent la base 2. Il existe d'autres ajustements qui permettent de représenter l'infini et NaN, et l'exposant est décalé (y reviendra), et un raccourci pour la mantisse (y reviendra aussi) . Recherchez la norme IEEE 754 qui couvre sa représentation et ses opérations pour plus de détails.

Pour nos besoins, nous pouvons l'imaginer comme un nombre binaire "mantisse" et un "exposant" qui vous indique où placer le séparateur décimal.


Dans le cas de Single, nous avons 1 bit pour le signe he, 8 pour l'exposant et 23 pour la mantisse.

Maintenant, le fait est que nous allons stocker la mantisse du chiffre le plus significatif. N'oubliez pas que tous les zéros à gauche ne sont pas pertinents. Et étant donné que nous travaillons en binaire, nous savons que le chiffre le plus significatif est un 1 ※. Eh bien, puisque nous le savons, nous n'avons pas à le stocker. Grâce à ce raccourci, la plage effective de la mantisse est de 24 bits.

※: À moins que le nombre que nous stockons soit nul. Pour cela, nous aurons tous les bits mis à zéro. Cependant, si nous essayons d'interpréter cela sous la description que j'ai donnée, vous auriez un 2 ^ 24 (le 1 implicite) multiplié par 1 (2 à la puissance de l'exposant 0). Donc, pour y remédier, l'exposant zéro est une valeur spéciale. Il existe également des valeurs spéciales pour stocker l'infini et NaN dans l'exposant.

Selon le décalage de l'exposant - en plus d'éviter les valeurs spéciales - son décalage permet de placer le point décimal avant le début de la mantisse ou après sa fin, sans avoir besoin d'avoir un signe pour l'exposant.


Cela signifie que pour les grands nombres, le type à virgule flottante placera le point décimal au-delà de la fin de la mantisse.

N'oubliez pas que la mantisse est un nombre de 24 bits. Il ne représentera jamais un nombre de 25 bits ... il n'a pas ce bit supplémentaire. Ainsi, le single ne peut pas distinguer entre 2 ^ 24 et 2 ^ 24 + 1 (ce sont les premiers nombres de 25 bits, et ils diffèrent sur le dernier bit, qui n'est pas représenté dans le single).

Ainsi, pour les entiers, la plage du simple est de -2 ^ 24 à 2 ^ 24. Et essayer d'ajouter 1 à 2 ^ 24 donnera 2 ^ 24 (car en ce qui concerne le type, 2 ^ 24 et 2 ^ 24 + 1 ont la même valeur). Essayez-le en ligne . C'est pourquoi il y a une perte d'informations lors de la conversion d'un entier en un seul. Et c'est aussi pourquoi une boucle qui utilise un simple ou un double pourrait en fait être une boucle infinie sans que vous vous en rendiez compte.

Theraot
la source
Ce n'est pas une explication parfaite du 1bit de tête implicite dans la signification. Elle est impliquée par le fait que le champ d'exposant biaisé est différent de zéro . Les subnormales (alias dénormales) ont notamment+-0.0 un 0bit de tête de leur signification. Je suppose que vous pourriez simplifier pour ne considérer 0.0qu'un cas totalement spécial, mais 0.0suit en fait les mêmes règles de codage que les autres sous-normales.
Peter Cordes
25

Voici un exemple réel de la perte de précision lors de la conversion de Integeren Single:

Le Singletype peut stocker tous les entiers de -16777216 à 16777216 (inclus), mais il ne peut pas stocker tous les entiers en dehors de cette plage. Par exemple, il ne peut pas stocker le numéro 16777217. En outre, il ne peut pas stocker de nombre impair supérieur à 16777216.

Nous pouvons utiliser Windows PowerShell pour voir ce qui se passe si nous convertissons un Integeren un Singleet inversement:

PS C:\Users\tanne> [int][float]16777213
16777213
PS C:\Users\tanne> [int][float]16777214
16777214
PS C:\Users\tanne> [int][float]16777215
16777215
PS C:\Users\tanne> [int][float]16777216
16777216
PS C:\Users\tanne> [int][float]16777217
16777216
PS C:\Users\tanne> [int][float]16777218
16777218
PS C:\Users\tanne> [int][float]16777219
16777220

Notez que 16777217 a été arrondi à 16777216 et 16777219 a été arrondi à 16777220.

Tanner Swett
la source
4
Et avec une magnitude croissante, la distance entre les floats représentables les plus proches continue de croître en tant que puissances de. en.wikipedia.org/wiki/…
Peter Cordes
12

Les types à virgule flottante sont similaires à la "notation scientifique" en physique. Le nombre est divisé en un bit de signe, un exposant (multiplicateur) et une mantisse (chiffres significatifs). Ainsi, lorsque l'amplitude de la valeur augmente, la taille du pas augmente également.

La virgule flottante simple précision a 23 bits de mantisse, mais il y a un "implicite 1", donc la mantisse est effectivement de 24 bits. Par conséquent, tous les entiers d'une magnitude allant jusqu'à 2 24 peuvent être représentés exactement en virgule flottante simple précision.

Au-dessus, on peut représenter successivement moins de nombres.

  • De 2 24 à 2 25, seuls les nombres pairs peuvent être représentés.
  • De 2 25 à 2 26, seuls les multiples de 4 peuvent être représentés.
  • De 2 26 à 2 27, seuls les multiples de 8 peuvent être représentés.
  • De 2 27 à 2 28, seuls les multiples de 16 peuvent être représentés
  • De 2 28 à 2 29 seuls les multiples de 32 peuvent être représentés
  • De 2 29 à 2 30 seuls les multiples de 64 peuvent être représentés
  • De 2 30 à 2 31 seuls les multiples de 128 peuvent être représentés

Ainsi, sur les 2 32 valeurs d'entier signées 32 bits possibles, seuls 2 * (2 24 + 7 * 2 23 ) = 9 * 2 24 peuvent être représentés en virgule flottante simple précision. Cela représente 3,515625% du total.

Peter Green
la source
8

Les flotteurs simple précision ont 24 bits de précision. Tout ce qui dépasse est arrondi au nombre de 24 bits le plus proche. Il pourrait être plus facile à comprendre en notation scientifique décimale, mais gardez à l'esprit que les flottants réels utilisent le binaire.

Supposons que vous disposez de 5 chiffres décimaux de mémoire. Vous pouvez choisir d'utiliser ceux comme un entier non signé régulier, vous permettant d'avoir n'importe quel nombre entre 0 et 99999. Si vous voulez pouvoir représenter des nombres plus grands, vous pouvez utiliser la notation scientifique et allouer simplement deux chiffres pour être l'exposant, donc vous pouvez désormais représenter n'importe quoi entre 0 et 9,99 x 10 99 .

Cependant, le plus grand nombre que vous pouvez représenter exactement n'est plus que 999. Si vous avez essayé de représenter 12345, vous pouvez obtenir 1,23 x 10 4 ou 1,24 x 10 4 , mais vous ne pouvez représenter aucun des nombres entre les deux, car vous n'ont pas assez de chiffres disponibles.

Karl Bielefeldt
la source
3
L'utilisation de chiffres décimaux est une bonne idée qui la rend plus facile à comprendre, mais le dernier paragraphe est un peu trompeur: en fait, vous pouvez représenter des nombres supérieurs à 999, et votre exemple le montre: 12300 serait 1,23 x 10 <sup> 4 <sup >. Vous voulez dire qu'à partir de ce nombre, il y a des lacunes. Pourriez-vous reformuler un peu?
Fabio dit Réintégrer Monica le