Así que obtuve la respuesta a mi última pregunta (no sé por qué no pensé en eso). Estaba imprimiendo un double
uso cout
que se redondeó cuando no lo esperaba. ¿Cómo puedo hacer cout
una impresión double
con total precisión?
Así que obtuve la respuesta a mi última pregunta (no sé por qué no pensé en eso). Estaba imprimiendo un double
uso cout
que se redondeó cuando no lo esperaba. ¿Cómo puedo hacer cout
una impresión double
con total precisión?
Respuestas:
Puede establecer la precisión directamente std::cout
y utilizar el std::fixed
especificador de formato.
double d = 3.14159265358979;
cout.precision(17);
cout << "Pi: " << fixed << d << endl;
Puede #include <limits>
obtener la máxima precisión de un flotador o doble.
#include <limits>
typedef std::numeric_limits< double > dbl;
double d = 3.14159265358979;
cout.precision(dbl::max_digits10);
cout << "Pi: " << d << endl;
cout.precision(numeric_limits<double>::digits10 + 2);
solo obtengo 16 ...
max_digits10
para denotar lo mismo. Se corrigió la respuesta para reflejar esto.
Uso std::setprecision
:
std::cout << std::setprecision (15) << 3.14159265358979 << std::endl;
std::setprecision (17)
doble, ver los comentarios en la respuesta de @Bill The Lizard.
Esto es lo que usaría:
std::cout << std::setprecision (std::numeric_limits<double>::digits10 + 1)
<< 3.14159265358979
<< std::endl;
Básicamente, el paquete de límites tiene rasgos para todos los tipos de compilación.
Uno de los rasgos para los números de coma flotante (flotante / doble / largo doble) es el atributo digits10. Esto define la precisión (se me olvida la terminología exacta) de un número de coma flotante en la base 10.
Consulte: http://www.cplusplus.com/reference/std/limits/numeric_limits.html
Para obtener detalles sobre otros atributos.
std::setprecision()
: #include <iomanip>
std::numeric_limits<double>
lugar denumberic_limits<double>
1
a std::numeric_limits<double>::digits10
?
max_digits10
, no algo arbitrario digits10+2
. De lo contrario, en el caso de float
, long double
, boost::multiprecision::float128
se producirá un error, ya que lo que se necesita +3
en lugar de +2
.
La forma de iostreams es un poco torpe. Prefiero usar boost::lexical_cast
porque calcula la precisión correcta para mí. Y también es rápido .
#include <string>
#include <boost/lexical_cast.hpp>
using boost::lexical_cast;
using std::string;
double d = 3.14159265358979;
cout << "Pi: " << lexical_cast<string>(d) << endl;
Salida:
Pi: 3.14159265358979
Con total precisión, supongo que la precisión es lo suficientemente mala como para mostrar la mejor aproximación al valor deseado, pero debe señalarse que double
se almacena utilizando la representación de base 2 y la base 2 no puede representar algo tan trivial como 1.1
exactamente. La única forma de obtener la precisión completa del doble real (sin ERROR DE REDONDEO) es imprimir los bits binarios (o nibbles hexadecimales). Una forma de hacerlo es escribir double
en union
ay luego imprimir el valor entero de los bits.
union {
double d;
uint64_t u64;
} x;
x.d = 1.1;
std::cout << std::hex << x.u64;
¡Esto le dará la precisión 100% precisa del doble ... y será completamente ilegible porque los humanos no pueden leer el formato doble IEEE! Wikipedia tiene una buena redacción sobre cómo interpretar los bits binarios.
En la versión más reciente de C ++, puedes hacer
std::cout << std::hexfloat << 1.1;
Aquí se explica cómo mostrar un doble con total precisión:
double d = 100.0000000000005;
int precision = std::numeric_limits<double>::max_digits10;
std::cout << std::setprecision(precision) << d << std::endl;
Esto muestra:
100.0000000000005
max_digits10 es el número de dígitos que son necesarios para representar de forma exclusiva todos los valores dobles distintos. max_digits10 representa el número de dígitos antes y después del punto decimal.
No use set_precision (max_digits10) con std :: fixed.
En notación fija, set_precision () establece el número de dígitos solo después del punto decimal. Esto es incorrecto ya que max_digits10 representa el número de dígitos antes y después del punto decimal.
double d = 100.0000000000005;
int precision = std::numeric_limits<double>::max_digits10;
std::cout << std::fixed << std::setprecision(precision) << d << std::endl;
Esto muestra un resultado incorrecto:
100.00000000000049738
Nota: Se requieren archivos de encabezado
#include <iomanip>
#include <limits>
100.0000000000005
no se representa exactamente como a double
. (Puede parecer que debería, pero no lo hace, porque se normaliza , es decir, su representación binaria). Para ver esto, trate de: 100.0000000000005 - 100
. Nosotros conseguimos 4.973799150320701e-13
.
¿Cómo imprimo un
double
valor con total precisión usando cout?
Usar hexfloat
o
usar scientific
y establecer la precisión
std::cout.precision(std::numeric_limits<double>::max_digits10 - 1);
std::cout << std::scientific << 1.0/7.0 << '\n';
// C++11 Typical output
1.4285714285714285e-01
Demasiadas respuestas abordan solo una de 1) base 2) diseño fijo / científico o 3) precisión. Demasiadas respuestas con precisión no proporcionan el valor adecuado necesario. De ahí esta respuesta a una vieja pregunta.
C double
está ciertamente codificado usando la base 2. Un enfoque directo con C ++ 11 es imprimir usando std::hexfloat
.
Si una salida no decimal es aceptable, hemos terminado.
std::cout << "hexfloat: " << std::hexfloat << exp (-100) << '\n';
std::cout << "hexfloat: " << std::hexfloat << exp (+100) << '\n';
// output
hexfloat: 0x1.a8c1f14e2af5dp-145
hexfloat: 0x1.3494a9b171bf5p+144
fixed
o scientific
?A double
es un tipo de punto flotante , no un punto fijo .
No , no utilice std::fixed
como que no se imprime pequeña double
como algo más 0.000...000
. Para grandes double
, imprime muchos dígitos, quizás cientos de informativos cuestionables.
std::cout << "std::fixed: " << std::fixed << exp (-100) << '\n';
std::cout << "std::fixed: " << std::fixed << exp (+100) << '\n';
// output
std::fixed: 0.000000
std::fixed: 26881171418161356094253400435962903554686976.000000
Para imprimir con total precisión, primero use el std::scientific
cual "escribirá valores de punto flotante en notación científica". Observe que el valor predeterminado de 6 dígitos después del punto decimal, una cantidad insuficiente, se maneja en el siguiente punto.
std::cout << "std::scientific: " << std::scientific << exp (-100) << '\n';
std::cout << "std::scientific: " << std::scientific << exp (+100) << '\n';
// output
std::scientific: 3.720076e-44
std::scientific: 2.688117e+43
Un double
codificado utilizando la base binaria 2 codifica la misma precisión entre varias potencias de 2. Esto suele ser de 53 bits.
[1.0 ... 2.0) hay 2 53 diferentes double
,
[2.0 ... 4.0) hay 2 53 diferentes double
,
[4.0 ... 8.0) hay 2 53 diferentes double
,
[8.0 ... 10.0) hay 2 / 8 * 2 53 diferentes double
.
Sin embargo, si las impresiones de código en decimal con N
dígitos significativos, el número de combinaciones [1.0 ... 10.0) es 9/10 * 10 N .
Cualquiera que sea la N
(precisión) elegida, no habrá un mapeo uno a uno entre double
y el texto decimal. Si N
se elige un fijo , a veces será un poco más o menos de lo realmente necesario para ciertos double
valores. Podríamos cometer un error en muy pocos ( a)
abajo) o demasiados ( b)
abajo).
3 candidato N
:
a) Use un N
so cuando convierta double
texto- -texto llegamos al mismo texto para todos double
.
std::cout << dbl::digits10 << '\n';
// Typical output
15
b) Use un N
so cuando convierta de double
-texto- double
llegamos a lo mismo double
para todos double
.
// C++11
std::cout << dbl::max_digits10 << '\n';
// Typical output
17
Cuando max_digits10
no está disponible, tenga en cuenta que debido a los atributos de base 2 y base 10 digits10 + 2 <= max_digits10 <= digits10 + 3
, podemos usar digits10 + 3
para asegurar que se impriman suficientes dígitos decimales.
c) Use un N
que varía con el valor.
Esto puede ser útil cuando el código quiere mostrar texto mínimo ( N == 1
) o el valor exacto de a double
( N == 1000-ish
en el caso de denorm_min
). Sin embargo, dado que esto es "trabajo" y no es probable que sea el objetivo de OP, se dejará de lado.
Generalmente es b) que se usa para "imprimir un double
valor con total precisión". Algunas aplicaciones pueden preferir a) al error al no proporcionar demasiada información.
Con .scientific
, .precision()
establece el número de dígitos para imprimir después del punto decimal, por lo que 1 + .precision()
se imprimen los dígitos. El código necesita max_digits10
dígitos totales, por lo que .precision()
se llama con a max_digits10 - 1
.
typedef std::numeric_limits< double > dbl;
std::cout.precision(dbl::max_digits10 - 1);
std::cout << std::scientific << exp (-100) << '\n';
std::cout << std::scientific << exp (+100) << '\n';
// Typical output
3.7200759760208361e-44
2.6881171418161356e+43
//1234567890123456 17 total digits
precision()
establece el número de lugares decimales para el modo científico. Sin especificar scientific
, establece el número total de dígitos, excluyendo el exponente. Aún puede terminar con resultados científicos, dependiendo de su valor numérico, pero también puede obtener menos dígitos de los que especificó. Ejemplo: Los cout.precision(3); cout << 1.7976931348623158e+308; // "1.8e+308"
resultados para printf
pueden ser diferentes. Cosas confusas que uno debe tener en cuenta.
char buf[DBL_DECIMAL_DIG + 3 + 5]; sprintf(buf, "%.*g", DBL_DECIMAL_DIG, d);
Los caracteres adicionales son para: signo, punto decimal, cero final, e [+ | -], 3 dígitos para el exponente ( DBL_MAX_10_EXP = 308). Por lo tanto, el número total de caracteres requeridos es 25.
printf("%.12f", M_PI);
% .12f significa punto flotante, con precisión de 12 dígitos.
Lo más portátil ...
#include <limits>
using std::numeric_limits;
...
cout.precision(numeric_limits<double>::digits10 + 1);
cout << d;
Con ostream :: precision (int)
cout.precision( numeric_limits<double>::digits10 + 1);
cout << M_PI << ", " << M_E << endl;
rendirá
3.141592653589793, 2.718281828459045
¿Por qué tienes que decir "+1"? No tengo idea, pero el dígito extra que obtienes es correcto.
Esto mostrará el valor hasta dos decimales después del punto.
#include <iostream>
#include <iomanip>
double d = 2.0;
int n = 2;
cout << fixed << setprecison(n) << d;
Ver aquí: notación de punto fijo
Usar notación de punto flotante fija Establece el indicador de formato de campo flotante para la secuencia str en fijo.
Cuando floatfield se establece en fijo, los valores de punto flotante se escriben usando notación de punto fijo: el valor se representa con exactamente tantos dígitos en la parte decimal como se especifica en el campo de precisión (precisión) y sin parte de exponente.
Establecer precisión decimal Establece la precisión decimal que se utilizará para formatear valores de punto flotante en las operaciones de salida.
Si está familiarizado con el estándar IEEE para representar los puntos flotantes, sabrá que es imposible mostrar los puntos flotantes con total precisión fuera del alcance del estándar , es decir, siempre resultará en Un redondeo del valor real.
Primero debe verificar si el valor está dentro del alcance , en caso afirmativo, luego use:
cout << defaultfloat << d ;
Usar notación de punto flotante predeterminada Establece el indicador de formato de campo flotante para la secuencia str en defaultfloat.
Cuando floatfield se establece en defaultfloat, los valores de punto flotante se escriben usando la notación predeterminada: la representación utiliza tantos dígitos significativos como sea necesario hasta la precisión decimal (precisión) de la secuencia, contando los dígitos antes y después del punto decimal (si corresponde) )
Ese es también el comportamiento predeterminado de cout
, lo que significa que no lo usa explícitamente.
fixed
? Condouble h = 6.62606957e-34;
,fixed
me da0.000000000000000
yscientific
salidas6.626069570000000e-34
.