¿Rangos de tipo de datos de punto flotante en C?

5 minutos de lectura

avatar de usuario
ipkiss

Estoy leyendo un libro de C, hablando de rangos de coma flotante, el autor dio la tabla:

Type     Smallest Positive Value  Largest value      Precision
====     =======================  =============      =========
float    1.17549 x 10^-38         3.40282 x 10^38    6 digits
double   2.22507 x 10^-308        1.79769 x 10^308   15 digits

No sé de dónde vienen los números en las columnas Positivo más pequeño y Valor más grande.

  • Vienen del rango del tipo de coma flotante.

    –Kendall Frey

    11 de abril de 2012 a las 14:34

  • La respuesta correcta pero inútil sería “IEEE 754”.

    – Jerry Ataúd

    11 de abril de 2012 a las 14:35

  • ¿Quieres decir por qué los límites son esos valores?

    – Señor Guy

    11 de abril de 2012 a las 14:35

  • ¿Es IEEE 754 requerido por el estándar C?

    – Foo

    11 de abril de 2012 a las 14:59

  • @foo, los formatos IEEE 754 son comunes y algunos libros tienden a no hacer una diferencia entre las características de implementación y el lenguaje requerido y algunas personas tienden a no prestar atención cuando el libro es claro que muestra características de una o varias implementaciones comunes que no son requeridos por el lenguaje.

    – Un programador

    11 de abril de 2012 a las 15:14


avatar de usuario
Andreas Brick

Un número de punto flotante de 32 bits tiene 23 + 1 bits de mantisa y un exponente de 8 bits (aunque se usa -126 a 127), por lo que el número más grande que puede representar es:

(1 + 1 / 2 + ... 1 / (2 ^ 23)) * (2 ^ 127) = 
(2 ^ 23 + 2 ^ 23 + .... 1) * (2 ^ (127 - 23)) = 
(2 ^ 24 - 1) * (2 ^ 104) ~= 3.4e38

  • Aquí te explico porque lo raro -126 para 127 rango que contiene solo 253 números y no los 255 esperados (uno es para infinito y el otro subnormal): stackoverflow.com/a/53204544/895245

    – Ciro Santilli Путлер Капут 六四事

    13 de noviembre de 2018 a las 13:20

Estos números provienen de la IEEE-754 estándar, que define la representación estándar de los números de coma flotante. Artículo de Wikipedia en el enlace explica cómo llegar a estos rangos conociendo el número de bits utilizados para los signos, la mantisa y el exponente.

avatar de usuario
señorGuy

Los valores para el tipo de datos flotante provienen de tener 32 bits en total para representar el número que se asigna de esta manera:

1 bit: bit de signo

8 bits: exponente p

23 bits: mantisa

El exponente se almacena como p + BIAS donde el BIAS es 127, la mantisa tiene 23 bits y un bit oculto número 24 que se supone 1. Este bit oculto es el bit más significativo (MSB) de la mantisa y se debe elegir el exponente para que sea 1.

Esto significa que el número más pequeño que puedes representar es 01000000000000000000000000000000 cual es 1x2^-126 = 1.17549435E-38.

El mayor valor es 011111111111111111111111111111111la mantisa es 2 * (1 – 1/65536) y el exponente es 127 lo que da (1 - 1 / 65536) * 2 ^ 128 = 3.40277175E38.

Los mismos principios se aplican a la doble precisión, excepto que los bits son:

1 bit: bit de signo

11 bits: bits de exponente

52 bits: bits de mantisa

SESGO: 1023

Entonces, técnicamente, los límites provienen del estándar IEEE-754 para representar números de coma flotante y lo anterior es cómo surgen esos límites.

  • Vale la pena mencionar que ese es el normal más pequeño, hay subnormales más pequeños: stackoverflow.com/a/53204544/895245

    – Ciro Santilli Путлер Капут 六四事

    13 de noviembre de 2018 a las 13:16


avatar de usuario
Ciro Santilli Путлер Капут 六四事

Infinito, NaN y subnormales

Estas son advertencias importantes que ninguna otra respuesta ha mencionado hasta ahora.

Primero lea esta introducción a IEEE 754 y números subnormales: ¿Qué es un número de punto flotante subnormal?

Luego, para flotadores de precisión simple (32 bits):

  • IEEE 754 dice que si el exponente es todos unos (0xFF == 255), entonces representa NaN o Infinity.

    Esta es la razón por la cual el mayor número no infinito tiene exponente 0xFE == 254 y no 0xFF.

    Luego, con el sesgo, se convierte en:

    254 - 127 == 127
    
  • FLT_MIN es el más pequeño normal número. ¡Pero hay subnormales más pequeños! Esos toman la -127 ranura de exponente.

Todas las afirmaciones del siguiente programa pasan en Ubuntu 18.04 amd64:

#include <assert.h>
#include <float.h>
#include <inttypes.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>

float float_from_bytes(
    uint32_t sign,
    uint32_t exponent,
    uint32_t fraction
) {
    uint32_t bytes;
    bytes = 0;
    bytes |= sign;
    bytes <<= 8;
    bytes |= exponent;
    bytes <<= 23;
    bytes |= fraction;
    return *(float*)&bytes;
}

int main(void) {
    /* All 1 exponent and non-0 fraction means NaN.
     * There are of course many possible representations,
     * and some have special semantics such as signalling vs not.
     */
    assert(isnan(float_from_bytes(0, 0xFF, 1)));
    assert(isnan(NAN));
    printf("nan                  = %e\n", NAN);

    /* All 1 exponent and 0 fraction means infinity. */
    assert(INFINITY == float_from_bytes(0, 0xFF, 0));
    assert(isinf(INFINITY));
    printf("infinity             = %e\n", INFINITY);

    /* ANSI C defines FLT_MAX as the largest non-infinite number. */
    assert(FLT_MAX == 0x1.FFFFFEp127f);
    /* Not 0xFF because that is infinite. */
    assert(FLT_MAX == float_from_bytes(0, 0xFE, 0x7FFFFF));
    assert(!isinf(FLT_MAX));
    assert(FLT_MAX < INFINITY);
    printf("largest non infinite = %e\n", FLT_MAX);

    /* ANSI C defines FLT_MIN as the smallest non-subnormal number. */
    assert(FLT_MIN == 0x1.0p-126f);
    assert(FLT_MIN == float_from_bytes(0, 1, 0));
    assert(isnormal(FLT_MIN));
    printf("smallest normal      = %e\n", FLT_MIN);

    /* The smallest non-zero subnormal number. */
    float smallest_subnormal = float_from_bytes(0, 0, 1);
    assert(smallest_subnormal == 0x0.000002p-126f);
    assert(0.0f < smallest_subnormal);
    assert(!isnormal(smallest_subnormal));
    printf("smallest subnormal   = %e\n", smallest_subnormal);

    return EXIT_SUCCESS;
}

GitHub ascendente.

Compilar y ejecutar con:

gcc -ggdb3 -O0 -std=c11 -Wall -Wextra -Wpedantic -Werror -o subnormal.out subnormal.c
./subnormal.out

Producción:

nan                  = nan
infinity             = inf
largest non infinite = 3.402823e+38
smallest normal      = 1.175494e-38
smallest subnormal   = 1.401298e-45

avatar de usuario
timoteo jones

Como ya respondió dasblinkenlight, los números provienen de la forma en que se representan los números de punto flotante en IEEE-754, y Andreas tiene un buen desglose de las matemáticas.

Sin embargo, tenga cuidado de que la precisión de los números de coma flotante no sea exactamente de 6 o 15 dígitos decimales significativos como sugiere la tabla, ya que la precisión de los números IEEE-754 depende de la cantidad de dígitos binarios significativos.

  • float tiene 24 dígitos binarios significativos, que según el número representado se traduce en 6-8 dígitos decimales de precisión.

  • double tiene 53 dígitos binarios significativos, que son aproximadamente 15 dígitos decimales.

Otra respuesta mía tiene más explicaciones si estás interesado.

avatar de usuario
Foo

Es una consecuencia del tamaño de la parte del exponente del tipo, como en IEEE 754 por ejemplo. Puede examinar los tamaños con FLT_MAX, FLT_MIN, DBL_MAX, DBL_MIN en float.h.

¿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