web-dev-qa-db-fra.com

Comment puis-je imprimer une valeur double avec une précision complète en utilisant cout?

J'ai donc eu la réponse à ma dernière question (je ne sais pas pourquoi je n'y ai pas pensé). J'imprimais une double à l'aide de cout qui a été arrondie lorsque je ne m'y attendais pas. Comment puis-je faire cout imprimer une double avec une précision maximale?

301
Jason Punyon

Vous pouvez définir la précision directement sur _std::cout_ et utiliser le spécificateur de format std::fixed .

_double d = 3.14159265358979;
cout.precision(17);
cout << "Pi: " << fixed << d << endl;
_

Vous pouvez _#include <limits>_ pour obtenir la précision maximale d'un float ou d'un double.

_#include <limits>

typedef std::numeric_limits< double > dbl;

double d = 3.14159265358979;
cout.precision(dbl::max_digits10);
cout << "Pi: " << d << endl;
_
355
Bill the Lizard

Utilisez std::setprecision :

_std::cout << std::setprecision (15) << 3.14159265358979 << std::endl;
_
63
Paul Beckingham

Voici ce que je voudrais utiliser:

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

Fondamentalement, le paquet de limites a des traits pour tous les types de construction.
L’un des traits des nombres à virgule flottante (float/double/long double) est l’attribut digits10. Ceci définit la précision (j'oublie la terminologie exacte) d'un nombre à virgule flottante en base 10.

Voir: http://www.cplusplus.com/reference/std/limits/numeric_limits.html
Pour plus de détails sur les autres attributs.

23
Martin York

La façon dont iostreams est assez maladroite. Je préfère utiliser boost::lexical_cast car il calcule la bonne précision pour moi. Et c'est rapide , aussi.

_#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;
_

Sortie:

Pi: 3.14159265358979

13
Timothy003

Voici comment afficher un double avec une précision absolue:

double d = 100.0000000000005;
int precision = std::numeric_limits<double>::max_digits10;
std::cout << std::setprecision(precision) << d << std::endl;

Cela affiche:

100.0000000000005


max_digits10 est le nombre de chiffres nécessaires pour représenter de manière unique toutes les valeurs doubles distinctes. max_digits10 représente le nombre de chiffres avant et après le point décimal.


N'utilisez pas set_precision (max_digits10) avec std :: fixed.
En notation fixe, set_precision () définit le nombre de chiffres niquement après le point décimal. Ceci est incorrect car max_digits10 représente le nombre de chiffres before et after le point décimal.

double d = 100.0000000000005;
int precision = std::numeric_limits<double>::max_digits10;
std::cout << std::fixed << std::setprecision(precision) << d << std::endl;

Cela affiche un résultat incorrect:

100.00000000000049738

Remarque: Fichiers d'en-tête requis

#include <iomanip>
#include <limits>
10
Daniel Laügt

Par pleine précision, je suppose que la précision moyenne est suffisante pour indiquer la meilleure approximation de la valeur recherchée, mais il convient de noter que double est stocké à l'aide de la représentation en base 2 et que la base 2 ne peut pas représenter quelque chose d'aussi trivial que 1.1 exactement. Le seul moyen d'obtenir la précision complète-complète du double actuel (avec NO ROUND OFF ERROR) consiste à imprimer les bits binaires (ou hex nybbles). ) Une façon de faire est d'écrire la double sur un union, puis d'afficher la valeur entière des bits.

union {
    double d;
    uint64_t u64;
} x;
x.d = 1.1;
std::cout << std::hex << x.u64;

Cela vous donnera la précision 100% précise du double ... et sera totalement illisible car les humains ne peuvent pas lire le double format IEEE! Wikipedia a une bonne écriture sur la façon d'interpréter les bits binaires.

En C++ plus récent, vous pouvez faire

std::cout << std::hexfloat << 1.1;
9
Mark Lakata

Comment imprimer une valeur double avec une précision complète en utilisant cout?

Utilisez hexfloat ou
utilise scientific et règle la précision

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

Trop de réponses ne traitent que de 1) la base 2) la mise en page fixe/scientifique ou 3) la précision. Trop de réponses avec la précision ne fournissent pas la valeur appropriée nécessaire. D'où cette réponse à une vieille question.

  1. Quelle base?

Une double est certainement encodée en base 2. Une approche directe avec C++ 11 consiste à imprimer en utilisant std::hexfloat.
Si une sortie non décimale est acceptable, nous avons terminé.

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. Sinon: fixed ou scientific?

Un double est un type à virgule flottante et non à virgule fixe .

Ne pas utilisez std::fixed car cela ne permet pas d’imprimer de petites double comme autre chose que 0.000...000. Pour les grands double, il affiche plusieurs chiffres, peut-être des centaines d'informations discutables.

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 

Pour imprimer avec une précision optimale, utilisez d’abord std::scientific, qui "écrira des valeurs à virgule flottante en notation scientifique". Notez que la valeur par défaut de 6 chiffres après le point décimal, un montant insuffisant, est traitée au point suivant.

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. Combien de précision (combien de chiffres au total)?

Un double codé à l'aide de la base binaire 2 code la même précision entre différentes puissances de 2. C'est souvent 53 bits.

[1.0 ... 2.0) il y a 253 différent double,
[2.0 ... 4.0) il y a 253 différent double,
[4.0 ... 8.0) il y a 253 différent double,
[8.0 ... 10.0) il y a 2/8 * 253 différent double.

Pourtant, si le code est imprimé en décimal avec N chiffres significatifs, le nombre de combinaisons [1.0 ... 10.0) est de 9/10 * 10N.

Quel que soit le choix de N (précision), il n’y aura pas de correspondance individuelle entre double et le texte décimal. Si un N fixe est choisi, il sera parfois légèrement plus ou moins que nécessaire pour certaines valeurs de double. Nous pourrions nous tromper sur trop peu (a) ci-dessous) ou trop souvent (b) ci-dessous).

3 candidats N:

a) Utilisez un N donc lors de la conversion de texte -double- texte, nous obtenons le même texte pour tous les double.

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

b) Utilisez un N donc lors de la conversion de double-text -double, nous arrivons au même double pour tout double.

// C++11
std::cout << dbl::max_digits10 << '\n';
// Typical output
17

Lorsque max_digits10 n'est pas disponible, notez qu'en raison des attributs de base 2 et 10, digits10 + 2 <= max_digits10 <= digits10 + 3, nous pouvons utiliser digits10 + 3 pour nous assurer que suffisamment de chiffres décimaux sont imprimés.

c) Utilisez un N variant avec la valeur.

Cela peut être utile lorsque le code veut afficher un texte minimal (N == 1) ou la valeur exacte d'un double (N == 1000-ish dans le cas de denorm_min). Pourtant, puisqu'il s'agit d'un "travail" et non d'un objectif probable pour OP, il sera mis de côté.


C'est généralement b) qui est utilisé pour "imprimer une valeur double avec une précision absolue". Certaines applications peuvent préférer a) commettre une erreur en ne fournissant pas trop d'informations.

Avec .scientific, .precision() définit le nombre de chiffres à imprimer après le point décimal, de sorte que 1 + .precision() chiffres soient imprimés. Le code nécessite max_digits10 nombre total de chiffres. .precision() est appelé avec 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

Question C similaire

4
chux
printf("%.12f", M_PI);

% .12f signifie une virgule flottante, avec une précision de 12 chiffres.

3
Maister

cout est un objet qui a un tas de méthodes que vous pouvez appeler pour changer la précision et le formatage des documents imprimés.

Il existe une opération setprecision (...), mais vous pouvez également définir d'autres paramètres tels que la largeur d'impression, etc.

Cherchez le cout dans la référence de votre IDE.

1
Uri

Avec ostream :: precision (int)

cout.precision( numeric_limits<double>::digits10 + 1);
cout << M_PI << ", " << M_E << endl;

va céder

3.141592653589793, 2.718281828459045

Pourquoi vous devez dire "+1" Je n'ai aucune idée, mais le chiffre supplémentaire que vous obtenez est correct.

0
Jann

Le plus portable ...

#include <limits>

using std::numeric_limits;

    ...
    cout.precision(numeric_limits<double>::digits10 + 1);
    cout << d;
0
mjmt