Impresión doble sin perder precisión

¿Cómo imprime un doble en una secuencia para que cuando se lea no pierda precisión?

Lo intenté:

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 que me sorprendió al pensar que digitos10 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 dos primeros no cuentan en (0.01).

Entonces, ¿alguien ha tratado de representar los números de coma flotante exactamente? ¿Cuál es el encantamiento mágico exacto en la secuencia que necesito hacer?

Después de algo de experimentación:

El problema fue con mi versión original. Hubo dígitos no significativos en la cadena después del punto decimal que afectaron la precisión.

Entonces, para compensar esto, podemos usar la notación científica para compensar:

ss << std::scientific
   << std::setprecision(std::numeric_limits<double>::digits10 + 1)
   << v;

Sin embargo, esto aún no explica la necesidad del +1.

Además, si imprimo el número con más precisión, ¡se imprime más precisión!

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";

En resultado de:

1.000000000000000e-02
1.0000000000000002e-02
1.00000000000000019428902930940239457413554200000000000e-02

Según la respuesta de @Stephen Canon a continuación:

Podemos imprimir exactamente usando el formateador printf (), "% a" o "% A". Para lograr esto en C ++ necesitamos usar 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?

Respuestas a la pregunta(6)

Su respuesta a la pregunta