Cuando la conversión de Integer a Single puede perder precisión

27

Estaba leyendo un artículo de Microsoft sobre Ampliación de conversiones y Opción estrictamente activada cuando llegué a la parte

Las siguientes conversiones pueden perder precisión:

  • Integer a Single
  • Largo a simple o doble
  • Decimal a simple o doble

Sin embargo, estas conversiones no pierden información o magnitud.

.. pero de acuerdo con otro artículo sobre tipos de datos ,

  • El tipo entero puede almacenar de -2.147.483.648 a 2.147.483.647 y

  • Solo tipo puede almacenar desde

    • 1,401298E-45 a 3,4028235E + 38 para números positivos,
    • y -3,4028235E + 38 a - 1,401298E-45 para números negativos

.. entonces Single puede almacenar muchos más números que Integer. No podía entender en qué situación tal conversión de Integer a Single puede perder precisión. ¿Podría alguien explicarme, por favor?

Vinicius V
fuente

Respuestas:

87

Single puede almacenar muchos más números que Integer

No, no puede Ambos Singley Integerson de 32 bits, lo que significa que ambos pueden almacenar exactamente la misma cantidad de números, es decir, 2 32 = 4294967296 números distintos.

Dado que el rango de Singlees claramente mayor que eso, es inmediatamente obvio (debido al Principio de Pigeonhole ) que no puede representar todos los números dentro de ese rango.

Y puesto que la gama de Integeres exactamente el mismo tamaño que la cantidad máxima de números que tanto Integery Singlepuede representar, pero Singletambién puede representar números fuera de ese rango, es evidente que no puede representar todos los números dentro de la gama de Integer.

Si hay algunos números de los Integerque no se puede representar Single, la conversión de Integera Single debe ser capaz de perder información.

Jörg W Mittag
fuente
3
+1 para esta gran explicación de por qué ese tiene que ser el caso, a pesar de que la pregunta era en realidad cuándo ("en qué situación") sucede ...
doubleYou
21
@doubleYou: 4261412864 de los 4294967296 Integers (99,2%) no se pueden representar como Single, por lo que "cuando" es "casi siempre".
Jörg W Mittag
2
Si quieres ser más preciso, Singlesolo puedes representar 4,278,190,079 números diferentes. Un Singlevalor representa un número si y solo si el exponente almacenado no es 255, lo que significa que hay 255 * 2 ^ 24 Singles que representan números. De estos, dos de ellos representan el mismo número (a saber, cero), y los otros representan números diferentes.
Tanner Swett
10
en.wikipedia.org/wiki/Single-precision_floating-point_format explica muy bien las limitaciones para IEEE754 binary32. Los enteros en [-16777216,16777216](2 ^ 24 = el ancho significativo) se pueden representar exactamente. Los números más grandes se redondean al múltiplo más cercano de 2, 4, 8, ... dependiendo de qué tan grandes sean.
Peter Cordes
14
“Lo que significa que ambos pueden almacenar exactamente la misma cantidad de números” - No , no significa eso. Solo significaría que si ambos tipos tienen exactamente el mismo número de formas de almacenar cada número. Y este no es el caso; por ejemplo, Singletiene dos formas de almacenar cero. Entonces Single, de hecho, puede representar menos números distintos que Integer.
Konrad Rudolph
28

Los tipos de punto flotante (como Single y Double) se representan en la memoria mediante un signo, una mantisa y un exponente. Piense en ello como notación científica:

Sign*Mantissa*Base^Exponent

Ellos, como es de esperar, usan la base 2. Hay otros ajustes que permiten representar el infinito y NaN, y el exponente está compensado (volverá a eso), y una abreviatura de la mantisa (volverá a eso también) . Busque el estándar IEEE 754 que cubre su representación y operaciones para obtener más detalles.

Para nuestros propósitos, podemos imaginarlo como un número binario "mantissa" y un "exponente" que le dice dónde colocar el separador decimal.


En el caso de Single, tenemos 1 bit para el signo, 8 para el exponente y 23 para la mantisa.

Ahora, la cosa es que almacenaremos la mantisa desde el dígito más significativo. Recuerde que todos los ceros a la izquierda no son relevantes. Y dado que estamos trabajando en binario, sabemos que el dígito más significativo es un 1 ※. Bueno, como sabemos eso, no tenemos que almacenarlo. Gracias a esa taquigrafía, el rango efectivo de la mantisa es de 24 bits.

※: A menos que el número que estamos almacenando sea cero. Para eso tendremos todos los bits puestos a cero. Sin embargo, si intentamos interpretar eso bajo la descripción que di, tendrías un 2 ^ 24 (el implícito 1) multiplicado por 1 (2 a la potencia del exponente 0). Entonces, para arreglarlo, el exponente cero es un valor especial. También hay valores especiales para almacenar infinito y NaN en el exponente.

Según el desplazamiento del exponente, además de evitar los valores especiales, tenerlo desplazado permite colocar el punto decimal antes del comienzo de la mantisa o después de su final, sin la necesidad de tener un signo para el exponente.


Esto significa que para números grandes, el tipo de coma flotante colocará el punto decimal más allá del final de la mantisa.

Recuerde que la mantisa es un número de 24 bits. Nunca representará un número de 25 bits ... no tiene ese bit extra. Por lo tanto, el single no puede distinguir entre 2 ^ 24 y 2 ^ 24 + 1 (estos son los primeros números de 25 bits, y difieren en el último bit, que no está representado en el single).

Por lo tanto, para enteros, el rango del single es -2 ^ 24 a 2 ^ 24. E intentar agregar 1 a 2 ^ 24 dará como resultado 2 ^ 24 (porque en lo que respecta al tipo, 2 ^ 24 y 2 ^ 24 + 1 son el mismo valor). Pruébalo en línea . Es por eso que hay una pérdida de información al convertir de entero a único. Y esta es también la razón por la cual un bucle que usa un simple o doble podría ser un bucle infinito sin que lo notes.

Theraot
fuente
Esta no es una explicación perfecta del 1bit inicial implícito en el significado. Está implícito en que el campo de exponente sesgado no es cero . Los subnormales (también conocidos como denormales) incluyen+-0.0 una parte importante 0de su significado. Supongo que podría simplificarse para considerar 0.0un caso totalmente especial, pero en 0.0realidad sigue las mismas reglas de codificación que otros subnormales.
Peter Cordes
25

Aquí hay un ejemplo real de cuando la conversión de Integera Singlepuede perder precisión:

El Singletipo puede almacenar todos los enteros desde -16777216 hasta 16777216 (inclusive), pero no puede almacenar todos los enteros fuera de este rango. Por ejemplo, no puede almacenar el número 16777217. Por lo demás, no puede almacenar ningún número impar mayor que 16777216.

Podemos usar Windows PowerShell para ver qué sucede si convertimos an Integeren ay Singleviceversa:

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

Observe que 16777217 se redondeó a 16777216 y 16777219 se redondeó a 16777220.

Tanner Swett
fuente
44
Y con una magnitud creciente, la distancia entre los representables más cercanos floatsigue creciendo como potencias de. en.wikipedia.org/wiki/…
Peter Cordes
12

Los tipos de punto flotante son similares a la "notación científica" en física. El número se divide en un bit de signo, un exponente (multiplicador) y una mantisa (dígitos significativos). Entonces, a medida que aumenta la magnitud del valor, también aumenta el tamaño del paso.

El punto flotante de precisión simple tiene 23 bits de mantisa, pero hay un "1 implícito", por lo que la mantisa es efectivamente de 24 bits. Por lo tanto, todos los enteros con una magnitud de hasta 2 24 se pueden representar exactamente en coma flotante de precisión simple.

Por encima de eso, sucesivamente se pueden representar menos números.

  • De 2 24 a 2 25 solo se pueden representar números pares.
  • De 2 25 a 2 26 solo se pueden representar múltiplos de 4.
  • De 2 26 a 2 27 solo se pueden representar múltiplos de 8.
  • De 2 27 a 2 28 solo se pueden representar múltiplos de 16
  • De 2 28 a 2 29 solo se pueden representar múltiplos de 32
  • De 2 29 a 2 30 solo se pueden representar múltiplos de 64
  • De 2 30 a 2 31 solo se pueden representar múltiplos de 128

Entonces, de los 2 32 posibles valores enteros con signo de 32 bits, solo 2 * (2 24 + 7 * 2 23 ) = 9 * 2 24 se pueden representar en coma flotante de precisión simple. Eso es 3.515625% del total.

Peter Green
fuente
8

Los flotadores de precisión simple tienen 24 bits de precisión. Cualquier cosa sobre eso se redondea al número de 24 bits más cercano. Puede ser más fácil de entender en notación científica decimal, pero tenga en cuenta que los flotadores reales usan binario.

Digamos que tiene 5 dígitos decimales de memoria. Puede elegir usarlos como un int sin signo regular, lo que le permite tener cualquier número entre 0 y 99999. Si desea poder representar números más grandes, puede usar notación científica y simplemente asignar dos dígitos para ser el exponente, por lo que ahora puede representar cualquier cosa entre 0 y 9.99 x 10 99 .

Sin embargo, el número más grande que puede representar exactamente ahora es solo 999. Si intentó representar 12345, puede obtener 1.23 x 10 4 , o 1.24 x 10 4 , pero no puede representar ninguno de los números intermedios, porque no tiene suficientes dígitos disponibles.

Karl Bielefeldt
fuente
3
El uso de dígitos decimales es una buena idea que lo hace más fácil de entender, pero el último párrafo es un poco engañoso: en realidad puede representar números superiores a 999, y su ejemplo lo muestra: 12300 sería 1.23 x 10 <sup> 4 <sup >. Lo que quieres decir es que a partir de ese número hay lagunas. ¿Te importaría reformularlo un poco?
Fabio dice Restablecer a Mónica el