Alors comment faire pour imprimer un double à un cours d'eau de sorte que quand il est lu, vous ne perdez pas de précision?
J'ai essayé:
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;
Cela n'a pas fonctionné comme je l'espérais.
Mais je peux augmenter la précision (ce qui m'a surpris car je pensais que digits10 était le max requis).
ss << std::setprecision(std::numeric_limits<T>::digits10 + 2) << v << " ";
// ^^^^^^ +2
Ainsi, il a à voir avec le nombre de chiffres significatifs et les 2 premiers ne comptent pas dans (0.01).
Donc, personne n'a cherché à représenter des nombres à virgule flottante exactement? Quelle est l'exacte incantation magique sur le stream que je dois faire?
Edit:
Après une période d'expérimentation.
Le problème était avec ma version d'origine, il y avait non de chiffres significatifs dans la chaîne de caractères après la virgule qui a affecté la précision.
Donc, pour compenser cela, nous pouvons utiliser la notation scientifique pour compenser:
ss << std::scientific
<< std::setprecision(std::numeric_limits<double>::digits10 + 1)
<< v;
Ce n'est toujours pas expliquer la nécessité pour le +1 si.
Aussi, si j'ai imprimer le nombre avec plus de précision je obtenir plus de précision imprimé!
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";
Résultats:
1.000000000000000e-02
1.0000000000000002e-02
1.00000000000000019428902930940239457413554200000000000e-02
Edit 2
Basé sur @Stephen Canon réponse ci-dessous:
Nous pouvons imprimer exactement par uisng le printf() formateur de table "%a" ou "%A". Pour atteindre cet en C++, nous devons utiliser les fixes et scientifiques des manipulateurs (voir n3225: 22.4.2.2.2p5 Tableau 88)
std::cout.flags(std::ios_base::fixed | std::ios_base::scientific);
std::cout << v;
Pour l'instant j'ai défini:
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);}
Prochaine. Comment gérons-nous NaN/Inf