¿Cómo puedo imprimir un valor doble con total precisión usando cout?


Así que he recibido la respuesta a mi última pregunta (No se por qué no pensé en eso). Estaba imprimiendo un double usando cout que se redondeó cuando no lo esperaba. ¿Cómo puedo hacer que cout imprima un double con total precisión?

Author: Community, 2009-02-16

11 answers

Puede establecer la precisión directamente en 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> para 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;
 323
Author: Bill the Lizard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-13 12:18:13

Uso std::setprecision:

std::cout << std::setprecision (15) << 3.14159265358979 << std::endl;
 52
Author: Paul Beckingham,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-28 12:48:50

Esto es lo que usaría:

std::cout << std::setprecision (std::numeric_limits<double>::digits10 + 1)
          << 3.14159265358979
          << std::endl;

Básicamente el paquete limits tiene rasgos para todos los tipos de compilación.
Uno de los rasgos para los números de coma flotante (float/double/long double) es el atributo digits10. Esto define la precisión (me olvido de la terminología exacta) de un número de coma flotante en base 10.

Véase: http://www.cplusplus.com/reference/std/limits/numeric_limits.html
Para más detalles sobre otros atributos.

 22
Author: Martin York,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-15 14:36:24

El camino de iostreams es un poco torpe. Prefiero usar boost::lexical_cast porque calcula la precisión correcta para mí. Y es rápido, también.

#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

 13
Author: Timothy003,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-08 05:33:14

Aquí es 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 necesarios para representar de forma única todos los valores dobles distintos. max_digits10 representa el número de dígitos antes y después del punto decimal.


No utilice set_precision (max_digits10) con std::fixed.
En notación fija, set_precision() establece el número de dígitos solo después de el punto decimal. Esto es incorrecto ya que max_digits10 representa el número de dígitos antes de y después de el 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

 8
Author: Daniel Laügt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-02 11:58:53

Por precisión total, asumo que significa suficiente precisión para mostrar la mejor aproximación al valor pretendido, pero debe señalarse que double se almacena utilizando la representación de base 2 y base 2 no puede representar algo tan trivial como 1.1 exactamente. La única manera de obtener la precisión full-full del doble real (sin ERROR DE REDONDEO) es imprimir los bits binarios (o nybbles hexadecimales). Una forma de hacerlo es escribir el double a un union y luego imprimir el entero valor 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% exacta del doble... y ser completamente ilegible porque los seres humanos no pueden leer IEEE doble formato ! Wikipedia tiene un buen artículo sobre cómo interpretar los bits binarios.

En C++ más reciente, puede hacer

std::cout << std::hexfloat << 1.1;
 7
Author: Mark Lakata,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-24 20:36:30
printf("%.12f", M_PI);

%.12f significa punto flotante, con una precisión de 12 dígitos.

 2
Author: Maister,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-24 17:34:56

Cout es un objeto que tiene un montón de métodos que puede llamar para cambiar la precisión y el formato de las cosas impresas.

Hay una setprecision(...), pero también puede establecer otras cosas como el ancho de impresión, etc.

Busca cout en la referencia de tu IDE.

 1
Author: Uri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-16 18:18:54

Muy portable...

#include <limits>

using std::numeric_limits;

    ...
    cout.precision(numeric_limits<double>::digits10 + 1);
    cout << d;
 0
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-16 18:39:43

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 ni idea, pero el dígito extra que obtienes es correcto.

 0
Author: Jann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-11 11:28:59

¿Cómo puedo imprimir un valor double con total precisión usando cout?

Use hexfloat o
utilice scientific y ajuste 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) disposición fija/científica o 3) precisión. Demasiadas respuestas con precisión no proporcionan el valor adecuado necesario. De ahí esta respuesta a una vieja pregunta.

  1. ¿Qué base?

A double ciertamente está codificada usando 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

  1. De lo contrario: fixed o scientific?

A double es un tipo de coma flotante, no de punto fijo.

Do not use std::fixed ya que no puede imprimir en pequeño double como nada menos que 0.000...000. Para grandes double, imprime muchos dígitos, quizás cientos de informatividad cuestionable.

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 completo precisión, primero use std::scientific que "escribirá valores de coma 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

  1. ¿Cuánta precisión (cuántos dígitos totales)?

Un double codificado usando 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 253 diferente double,
[2.0...4.0) hay 253 diferente double,
[4.0...8.0) hay 253 diferente double,
[8.0...10.0) hay 2/8 * 253 diferente double.

Sin embargo, si el código se imprime en decimal con N dígitos significativos, el número de combinaciones [1.0...10.0) es 9/10 * 10N.

Cualquiera que sea N (precisión) que se elija, no habrá un mapeo uno a uno entre double y el texto decimal. Si un fijo se elige N, a veces será ligeramente más o menos de lo que realmente se necesita para ciertos valores double. Podríamos errar en muy pocos (a) abajo) o demasiados (b) abajo).

3 candidato N:

A) Use un N así que al convertir de text-double-text llegamos al mismo texto para todos double.

std::cout << dbl::digits10 << '\n';
// Typical output
15

B) Use un N así que al convertir de double-text-double llegamos al 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 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) Utilice un N que varía con el valor.

Esto puede ser útil cuando el código quiere mostrar un texto mínimo (N == 1) o el valor exacto de un double (N == 1000-ish en el caso de denorm_min). Sin embargo, dado que esto es "trabajo" y probablemente no es el objetivo de OP, se dejará de lado.


Generalmente es b) que se usa para "imprimir un valor double con total precisión". Algunas aplicaciones pueden preferir a) a error al no proporcionar demasiada información.

Con .scientific, .precision() establece el número de dígitos a 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 un 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

Similar C question

 0
Author: chux,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-12 16:40:46