c++ - que - ¿Cuál es la longitud máxima en caracteres necesaria para representar cualquier valor doble?
float c++ ejemplos (10)
Cuando convierto un int sin firmar de 8 bits a cadena, sé que el resultado siempre será como máximo 3 caracteres (para 255) y para un int firmado de 8 bits necesitamos 4 caracteres para, por ejemplo, "-128".
Ahora, lo que realmente me pregunto es lo mismo para los valores de punto flotante. ¿Cuál es el número máximo de caracteres necesarios para representar cualquier valor "doble" o "flotante" como una cadena?
Supongamos un doble C / C ++ normal (IEEE 754) y una expansión decimal normal (es decir, sin formato de% e printf).
¿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 números enteros)?
"¿Cuál es la longitud máxima en caracteres necesaria para representar cualquier valor doble?"
La respuesta exacta a esta pregunta es: 8 caracteres ASCII: en formato hexadimal, 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 fines educativos, las representaciones más largas son un desperdicio de recursos y potencia de cálculo:
Los usuarios no se están informando más 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 ese número destruirá la precisión. (excluyendo cambiar el bit de signo)
Si alguien necesita una mejor precisión real , entonces hay un doble de 80 bits de largo con una precisión de alrededor de 18 dígitos o fe libquadmath.
Saludos.
"Para eso necesitarás exactamente 325 caracteres"
Aparentemente (y este es un caso muy común) No entiendes 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 arquitecturas similares)
Por esa razón, se han inventado bibliotecas aritméticas de precisión arbitraria especializadas, como fe gmp o mpfr.
1024 no es suficiente, el valor doble negativo más pequeño tiene 1077 dígitos decimales. Aquí hay un código 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 programa.
1077
-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004940656458412465441765687928682213723650598026143247644255856825006755072702087518652998363616359923797965646954457177309266567103559397963987747960107818781263007131903114045278458171678489821036887186360569987307230500063874091535649843873124733972731696151400317153853980741262385655911710266585566867681870395603106249319452715914924553293054565444011274801297099995419319894090804165633245247571478690147267801593552386115501348035264934720193790268107107491703332226844753335720832431936092382893458368060106011506169809753078342277318329247904982524730776375927247874656084778203734469699533647017972677717585125660551199131504891101451037862738167250955837389733598993664809941164205702637090279242767544565229087538682506419718265533447265625
Depende de lo que quiere decir con "representar". La fracción decimal no tiene representaciones exactas de punto flotante. Cuando convierte la 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 involucra el posible problema de truncamiento. ¿Qué significa "exacto" en estas circunstancias?
Básicamente, depende de su representación en 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 (aproximadamente 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.
El encabezado estándar <float.h>
en C, o <cfloat>
en C ++, contiene varias constantes relacionadas con el rango y otras métricas de los tipos de punto 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 mayor que el número de dígitos necesarios para representar el mayor valor de mantisa 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 ver (y probar por inducción) que -pow(2,-N)
necesita 3+N
caracteres para una representación decimal no científica ( "-0."
, Seguida de N
dígitos). Así que 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
El número máximo de caracteres que se requerirán para imprimir cualquier double
valor decimal (es decir, en formato "%f"
) será para el valor de -DBL_MIN
(es decir, -0x1p-1022, asumiendo que el binario IEEE 754 es su double
). Para eso necesitarás exactamente 325 caracteres. Eso es: 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 principal a la izquierda del lugar decimal), y ese es el número de ceros iniciales 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);
Puede controlar el número de dígitos en la representación de la cadena cuando convierte el float / double en una cadena al establecer la precisión. El número máximo de dígitos sería igual a la representación de cadena de std::numeric_limits<double>::max()
en la precisión que especifique.
#include <iostream>
#include <limits>
#include <sstream>
#include <iomanip>
int main()
{
double x = std::numeric_limits<double>::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, el mayor número de dígitos en un double
con una precisión de 10 es 320 dígitos.
Puede usar snprintf()
para verificar cuántos caracteres necesita. snprintf()
devuelve la cantidad de caracteres necesarios para imprimir lo que se le pase.
/* NOT TESTED */
#include <stdio.h>
#include <stdlib.h>
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 compilador C89 lo proporciona como una extensión, es posible que no haga lo que el programa anterior espera.
Edición : se 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 de nuevo al sitio POSIX que prefiero sobre el sitio de la primera edición .
Según 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 .
Una fuente correcta de información que entra en más detalles 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:
Conteo Decimal Máximo de la Porción Integral
| Single| Double | Extended | Quad |
|:-----:|:------:|:--------:|:-----:|
| 9 | 17 | 21 | 36 |
* Quantities listed in decimals.
Los conteos de decimales se basan en la fórmula: a lo sumo decimales de Techo (1 + N Log_10 (2)), donde N es el número de bits en la parte integral *.
Longitudes máximas de exponentes
| Single| Double | Extended | Quad |
|:-----:|:------:|:--------:|:-----:|
| 5 | 5 | 7 | 7 |
* Standard format is `e-123`.
Algoritmo más rápido
El algoritmo más rápido para imprimir números de punto flotante es el algoritmo Grisu2 que se detalla en el documento de investigación Cómo imprimir números de punto flotante de manera rápida y precisa . El mejor punto de referencia que pude encontrar se puede encontrar here .