¿Cómo se imprime un doble en una secuencia para que cuando se lea no pierda precisión?Impresión doble sin perder precisión
me trataron:
std::stringstream ss;
double v = 0.1 * 0.1;
ss << std::setprecision(std::numeric_limits<T>::digits10) << v << " ";
double u;
ss >> u;
std::cout << "precision " << ((u == v) ? "retained" : "lost") << std::endl;
Esto no funcionó como esperaba.
Pero puedo aumentar la precisión (lo cual me sorprendió ya que pensé que digits10 era el máximo requerido).
ss << std::setprecision(std::numeric_limits<T>::digits10 + 2) << v << " ";
// ^^^^^^ +2
Tiene que ver con el número de dígitos significativos y los primeros dos no cuentan (0.01).
¿Alguien ha considerado representar los números de punto flotante exactamente? ¿Cuál es el conjuro mágico exacto en la transmisión que debo hacer?
Después de algunos experimentos:
El problema era con mi versión original. Hubo dígitos no significativos en la cadena después del punto decimal que afectó la precisión.
Así que para compensar esto podemos usar la notación científica para compensar:
ss << std::scientific
<< std::setprecision(std::numeric_limits<double>::digits10 + 1)
<< v;
Esto todavía no explica la necesidad de que el 1 aunque.
¡También si imprimo el número con más precisión obtengo más precisión impresa!
std::cout << std::scientific << std::setprecision(std::numeric_limits<double>::digits10) << v << "\n";
std::cout << std::scientific << std::setprecision(std::numeric_limits<double>::digits10 + 1) << v << "\n";
std::cout << std::scientific << std::setprecision(std::numeric_limits<double>::digits) << v << "\n";
el resultado es:
1.000000000000000e-02
1.0000000000000002e-02
1.00000000000000019428902930940239457413554200000000000e-02
Basado en @Stephen Canon respuesta a continuación:
podemos imprimir exactamente utilizando el formateador printf(), "% a" o "% UN". Para lograr esto en C++ que tenemos que utilizar los manipuladores fijos y científicos (ver N3225: 22.4.2.2.2p5 Tabla 88)
std::cout.flags(std::ios_base::fixed | std::ios_base::scientific);
std::cout << v;
Por ahora he definido:
template<typename T>
std::ostream& precise(std::ostream& stream)
{
std::cout.flags(std::ios_base::fixed | std::ios_base::scientific);
return stream;
}
std::ostream& preciselngd(std::ostream& stream){ return precise<long double>(stream);}
std::ostream& precisedbl(std::ostream& stream) { return precise<double>(stream);}
std::ostream& preciseflt(std::ostream& stream) { return precise<float>(stream);}
siguiente: ¿Cómo manejamos NaN/Inf?
¿Por qué está incluyendo un espacio después de 'v' al salir a' ss'? – chrisaycock
@chrisaycock: No hay razón. Cortar y pegar el error. –
Siempre habrá una pérdida de precisión, excepto aquellos valores que tienen un denomenador binario. La pregunta debería ser * ¿Cuánta precisión se debe mantener? * –