Convierta INT_MAX a flotante y luego de vuelta a entero.

4 minutos de lectura

Convierta INT MAX a flotante y luego de vuelta a entero
houtoms

En la programación en C, encuentro un problema extraño que contradice mi intuición. Cuando declaro un integer como el INT_MAX (2147483647definido en los límites.h) e implícitamente convertirlo en un float value, funciona bien, es decir, el valor flotante es el mismo que el entero máximo. Y luego, convierto el flotante nuevamente en un entero, sucede algo interesante. El nuevo integer se convierte en el entero mínimo (-2147483648).
Los códigos fuente se ven a continuación:

int a = INT_MAX;
float b = a; // b is correct
int a_new = b; // a_new becomes INT_MIN

No estoy seguro de lo que sucede cuando el número flotante b se convierte al entero a_new. Entonces, ¿hay alguna solución razonable para encontrar el valor máximo que se puede cambiar hacia adelante y hacia atrás entre integer y float ¿escribe?

PD: El valor de INT_MAX – 100 funciona bien, pero esto es solo una solución arbitraria.

  • el punto flotante solo tiene una precisión limitada, por lo que no creo que esta conversión sea extraña.

    – ymonad

    2 de mayo de 2014 a las 4:58

  • Contrariamente a tu comentario, b es no correcto. Si lo miras de cerca, creo que encontrarás que en realidad es INT_MAX+1 después de la primera conversión. INT_MAX en su plataforma es 2147483647, no 2147483648. Es decir, el primero la conversión es donde se introduce por primera vez el delta resultante. Véalo en vivo

    – WhozCraig

    2 de mayo de 2014 a las 5:02


  • Un flotante de 4 bytes usa 23 bits para almacenar la mantisa y 9 para almacenar el signo y el exponente. Esto significa que el almacenamiento de los enteros de 32 bits más grandes no se puede realizar con total precisión.

    –Jonathan Leffler

    2 de mayo de 2014 a las 5:14

  • Parece que el problema no ocurre en todas las plataformas: ver ejemplo aquí

    – Aurelien Gasser

    2 de mayo de 2014 a las 5:19

  • @AurélienGasser Es una falacia. Estoy seguro de que el compilador optimiza por defecto. Deshabilite las optimizaciones y luego vea los resultados. El número en cuestión no se puede representar exactamente como un punto flotante, por lo que no hay forma de recuperarlo.

    – devnull

    2 de mayo de 2014 a las 5:31

Esta respuesta supone que float es un flotador de precisión simple IEEE-754 codificado como 32 bits, y que un int es de 32 bits. Ver este artículo de Wikipedia para obtener más información sobre IEEE-754.


Los números de coma flotante solo tienen 24 bits de precisión, en comparación con los 32 bits de un int. Por lo tanto, los valores int de 0 a 16777215 tienen una representación exacta como números de punto flotante, pero los números mayores que 16777215 no necesariamente tienen representaciones exactas como flotantes. El siguiente código demuestra este hecho (en sistemas que usan IEEE-754).

for ( int a = 16777210; a < 16777224; a++ )
{
    float b = a;
    int c = b;
    printf( "a=%d c=%d b=0x%08x\n", a, c, *((int*)&b) );
}

La salida esperada es

a=16777210 c=16777210 b=0x4b7ffffa
a=16777211 c=16777211 b=0x4b7ffffb
a=16777212 c=16777212 b=0x4b7ffffc
a=16777213 c=16777213 b=0x4b7ffffd
a=16777214 c=16777214 b=0x4b7ffffe
a=16777215 c=16777215 b=0x4b7fffff
a=16777216 c=16777216 b=0x4b800000
a=16777217 c=16777216 b=0x4b800000
a=16777218 c=16777218 b=0x4b800001
a=16777219 c=16777220 b=0x4b800002
a=16777220 c=16777220 b=0x4b800002
a=16777221 c=16777220 b=0x4b800002
a=16777222 c=16777222 b=0x4b800003
a=16777223 c=16777224 b=0x4b800004

Lo interesante aquí es que el float el valor 0x4b800002 se usa para representar los tres int valores 16777219, 16777220 y 16777221, y así convertir 16777219 en un float y de vuelta a un int no conserva el valor exacto de la int.


Los dos valores de coma flotante más cercanos a INT_MAX son 2147483520 y 2147483648, que se pueden demostrar con este código

for ( int a = 2147483520; a < 2147483647; a++ )
{
    float b = a;
    int c = b;
    printf( "a=%d c=%d b=0x%08x\n", a, c, *((int*)&b) );
}

Las partes interesantes de la salida son

a=2147483520 c=2147483520 b=0x4effffff
a=2147483521 c=2147483520 b=0x4effffff
...
a=2147483582 c=2147483520 b=0x4effffff
a=2147483583 c=2147483520 b=0x4effffff
a=2147483584 c=-2147483648 b=0x4f000000
a=2147483585 c=-2147483648 b=0x4f000000
...
a=2147483645 c=-2147483648 b=0x4f000000
a=2147483646 c=-2147483648 b=0x4f000000

Tenga en cuenta que todos los de 32 bits int los valores de 2147483584 a 2147483647 se redondearán a un float valor de 2147483648. El mayor int el valor que se redondeará hacia abajo es 2147483583, que es lo mismo que (INT_MAX - 64) en un sistema de 32 bits.

Uno podría concluir, por lo tanto, que los números debajo de (INT_MAX - 64) se convertirá con seguridad de int para float y de vuelta a int. Pero eso solo es cierto en sistemas donde el tamaño de un int es de 32 bits, y un float está codificado por IEEE-754.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad