¿Cuál es la longitud máxima en caracteres necesarios para representar cualquier valor doble?

Cuando convierto un int de 8 bits sin signo en una cadena, sé que el resultado será como máximo de 3 caracteres (para 255) y para un int. De 8 bits firmado, necesitamos 4 caracteres para, por ejemplo, “-128”.

Ahora lo que realmente me pregunto es lo mismo para los valores de coma flotante. ¿Cuál es la cantidad máxima de caracteres necesarios para representar cualquier valor “doble” o “flotante” como una cadena?

Supongamos que un C / C ++ doble regular (IEEE 754) y una expansión decimal normal (es decir, no% e printf-formateo).

Ni siquiera estoy seguro de si el número realmente pequeño (es decir, 0.234234) será más largo que los números realmente grandes (los dobles representan los números enteros)?

El encabezado estándar en C, o en C ++, contiene varias constantes para hacer con el rango y otras métricas de los tipos de coma flotante. Uno de estos es DBL_MAX_10_EXP , el mayor exponente de potencia de 10 necesario para representar todos los valores double . Como 1eN necesita N+1 dígitos para representar, y también puede haber un signo negativo, entonces la respuesta es

 int max_digits = DBL_MAX_10_EXP + 2; 

Esto supone que el exponente es más grande que la cantidad de dígitos necesarios para representar el valor de mantisa más grande posible; de lo contrario, también habrá un punto decimal seguido de más dígitos.

CORRECCIÓN

El número más largo es en realidad el número negativo representable más pequeño: necesita suficientes dígitos para cubrir tanto el exponente como la mantisa. Este valor es -pow(2, DBL_MIN_EXP - DBL_MANT_DIG) , donde DBL_MIN_EXP es negativo. Es bastante fácil de ver (y probar por inducción) que -pow(2,-N) necesita 3+N caracteres para una representación decimal no científica ( "-0." , Seguido de N dígitos). Entonces la respuesta es

 int max_digits = 3 + DBL_MANT_DIG - DBL_MIN_EXP 

Para un doble IEEE de 64 bits, tenemos

 DBL_MANT_DIG = 53 DBL_MIN_EXP = -1023 max_digits = 3 + 53 - (-1023) = 1079 

De acuerdo con IEEE 754-1985 , la notación más larga para el valor representado por el tipo doble, es decir:

-2.2250738585072020E-308

tiene 24 caracteres .

Puede usar snprintf() para verificar cuántos caracteres necesita. snprintf() devuelve el número de caracteres necesarios para imprimir lo que se le pasa.

 /* NOT TESTED */ #include  #include  int main(void) { char dummy[1]; double value = 42.000042; /* or anything else */ int siz; char *representation; siz = snprintf(dummy, sizeof dummy, "%f", value); printf("exact length needed to represent 'value' " "(without the '\\0' terminator) is %d.\n", siz); representation = malloc(siz + 1); if (representation) { sprintf(representation, "%f", value); /* use `representation` */ free(representation); } else { /* no memory */ } return 0; } 

Nota : snprintf() es una función C99. Si un comstackdor C89 lo proporciona como una extensión, puede que no haga lo que el progtwig anterior espera.

Editar : Cambió el enlace a snprintf() por uno que realmente describe la funcionalidad impuesta por el estándar C99; la descripción en el enlace original es incorrecta.
2013: Cambié el enlace al sitio POSIX que prefiero sobre el sitio de la primera edición .

Puede controlar el número de dígitos en la representación de cadena cuando convierte el float / double en una cadena estableciendo la precisión. El número máximo de dígitos sería igual a la representación de cadena de std::numeric_limits::max() con la precisión que especifique.

 #include  #include  #include  #include  int main() { double x = std::numeric_limits::max(); std::stringstream ss; ss << std::setprecision(10) << std::fixed << x; std::string double_as_string = ss.str(); std::cout << double_as_string.length() << std::endl; } 

Por lo tanto, la mayor cantidad de dígitos en un double con una precisión de 10 es de 320 dígitos.

Depende de lo que quiere decir con “representar”. La fracción decimal no tiene representaciones exactas de coma flotante. Cuando convierte fracción decimal -> fracción binaria -> decimal, no tiene representaciones decimales exactas y tendrá bits de ruido al final de la representación binaria.

La pregunta no involucraba comenzar desde el decimal, pero todo el código fuente (y debe ser ingresado por el usuario) es decimal e implica el posible problema de truncamiento. ¿Qué significa “exacto” en estas circunstancias?

Básicamente, depende de tu representación de coma flotante.

Si tiene 48 bits de mantisa, esto toma alrededor de 16 dígitos decimales. El exponente podría ser los 14 bits restantes (alrededor de 5 dígitos decimales).

La regla de oro es que el número de bits es aproximadamente 3 veces el número de dígitos decimales.

1024 no es suficiente, el valor doble negativo más pequeño tiene 1077 dígitos decimales. Aquí hay algunos códigos Java.

 double x = Double.longBitsToDouble(0x8000000000000001L); BigDecimal bd = new BigDecimal(x); String s = bd.toPlainString(); System.out.println(s.length()); System.out.println(s); 

Aquí está la salida del progtwig.

 1077 -0. 

“¿Cuál es la longitud máxima en caracteres necesarios para representar cualquier valor doble?”

La respuesta exacta a esta pregunta es: 8 caracteres ASCII – en formato hexadicimal, excluyendo el prefijo ‘0x’ – 100% de precisión 🙂 (pero no es solo una broma)

La precisión utilizable del doble IEEE-754 es de alrededor de 16 dígitos decimales, por lo que excluyendo los propósitos educativos, las representaciones más largas son solo un desperdicio de recursos y poder de cómputo:

  • Los usuarios no están más informados cuando ven un número de 700 dígitos en la pantalla.

  • Las variables de configuración almacenadas en esa forma “más precisa” son inútiles: cada operación en tal número destruirá la precisión. (excluyendo el cambio del bit de signo)

Si alguien necesita una mejor precisión real , entonces hay un doble largo de 80 bits con una precisión de alrededor de 18 dígitos o fe libquadmath.

Saludos.

Una fuente correcta de información que entra en más detalle que la Especificación IEEE-754 son estas notas de la conferencia de UC Berkely en la página 4, más un poco de cálculos de bricolaje. Estas diapositivas de conferencias también son buenas para estudiantes de ingeniería.

Tamaños de tampón recomendados

 | Single| Double | Extended | Quad | |:-----:|:------:|:--------:|:-----:| | 16 | 24 | 30 | 45 | 

Estos números se basan en los siguientes cálculos:

Recuento máximo de decimales de la porción integral

 | Single| Double | Extended | Quad | |:-----:|:------:|:--------:|:-----:| | 9 | 17 | 21 | 36 | * Quantities listed in decimals. 

Los recuentos de decimales se basan en la fórmula: como máximo en decimales de Techo (1 + N Log_10 (2)), donde N es el número de bits en la parte integral *.

Longitud máxima de exponente

 | Single| Double | Extended | Quad | |:-----:|:------:|:--------:|:-----:| | 5 | 5 | 7 | 7 | * Standard format is `e-123`. 

El algoritmo más rápido

El algoritmo más rápido para imprimir números de coma flotante es el algoritmo Grisu2 detallado en el documento de investigación Impresión de números de coma flotante de forma rápida y precisa . El mejor punto de referencia que pude encontrar se puede encontrar aquí .

La cantidad máxima de caracteres que se requerirá para imprimir cualquier valor double decimal (es decir, en formato "%f" ) será para el valor de -DBL_MIN (es decir, -0x1p-1022, suponiendo que binary64 IEEE 754 es el double ). Para eso, necesitarás exactamente 325 caracteres. Es decir: DBL_DIG + abs(DBL_MIN_10_EXP) + strlen("-0.") . Esto es, por supuesto, porque log10(fabs(DBL_MIN)) es 308, que también es abs(DBL_MIN_10_EXP)+1 (el +1 se debe al dígito abs(DBL_MIN_10_EXP)+1 a la izquierda del lugar decimal), y ese es el número de ceros a la izquierda a la izquierda de los dígitos significativos.

 int lz; /* aka abs(DBL_MIN_10_EXP)+1 */ int dplaces; int sigdig; /* aka DBL_DECIMAL_DIG - 1 */ double dbl = -DBL_MIN; lz = abs((int) lrint(floor(log10(fabs(dbl))))); sigdig = lrint(ceil(DBL_MANT_DIG * log10((double) FLT_RADIX))); dplaces = sigdig + lz - 1; printf("f = %.*f\n", dplaces, dbl); 

“Para eso, necesitarás exactamente 325 caracteres”

Aparentemente (y este es un caso muy común) Usted no entiende cómo funciona la conversión entre diferentes bases numéricas.

No importa cuán precisa sea la definición de DBL_MIN, está limitada por la precisión del hardware, que suele ser de hasta 80 bits o 18 dígitos decimales (x86 y architectures similares)

Por esa razón, se han inventado bibliotecas de aritmética de precisión arbitraria especializada, como fe gmp o mpfr.