Quindi ho ottenuto la risposta alla mia ultima domanda (non so perché non ci abbia pensato). Stavo stampando un double
uso cout
arrotondato quando non me lo aspettavo. Come posso fare cout
una stampa double
usando la massima precisione?
Quindi ho ottenuto la risposta alla mia ultima domanda (non so perché non ci abbia pensato). Stavo stampando un double
uso cout
arrotondato quando non me lo aspettavo. Come posso fare cout
una stampa double
usando la massima precisione?
Risposte:
È possibile impostare la precisione direttamente std::cout
e utilizzare l' std::fixed
identificatore di formato.
double d = 3.14159265358979;
cout.precision(17);
cout << "Pi: " << fixed << d << endl;
È possibile #include <limits>
ottenere la massima precisione di un galleggiante o doppio.
#include <limits>
typedef std::numeric_limits< double > dbl;
double d = 3.14159265358979;
cout.precision(dbl::max_digits10);
cout << "Pi: " << d << endl;
cout.precision(numeric_limits<double>::digits10 + 2);
ottengo solo 16 ....
max_digits10
per indicare lo stesso. Risolto il problema con la risposta.
Utilizzare std::setprecision
:
std::cout << std::setprecision (15) << 3.14159265358979 << std::endl;
std::setprecision (17)
per doppio, vedere i commenti sulla risposta di @Bill The Lizard.
Ecco cosa vorrei usare:
std::cout << std::setprecision (std::numeric_limits<double>::digits10 + 1)
<< 3.14159265358979
<< std::endl;
Fondamentalmente il pacchetto limits ha tratti per tutti i tipi di build.
Uno dei tratti per i numeri in virgola mobile (float / double / long double) è l'attributo digits10. Questo definisce l'accuratezza (dimentico la terminologia esatta) di un numero in virgola mobile nella base 10.
Vedi: http://www.cplusplus.com/reference/std/limits/numeric_limits.html
Per dettagli su altri attributi.
std::setprecision()
: #include <iomanip>
std::numeric_limits<double>
invece dinumberic_limits<double>
1
a std::numeric_limits<double>::digits10
?
max_digits10
. Vedere questo .
max_digits10
, non un po 'arbitrario digits10+2
. In caso contrario, nel caso di float
, long double
, boost::multiprecision::float128
questo fallirà, dal momento che ci avresti bisogno +3
invece di +2
.
La via degli iostreams è piuttosto goffa. Preferisco usareboost::lexical_cast
perché calcola la giusta precisione per me. Ed è anche veloce .
#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;
Produzione:
Pi: 3.14159265358979
Con la massima precisione, suppongo che la precisione sia sufficiente per mostrare la migliore approssimazione al valore desiderato, ma va sottolineato che double
è memorizzato usando la rappresentazione di base 2 e la base 2 non può rappresentare qualcosa di così banale come 1.1
esattamente. L'unico modo per ottenere la piena precisione del doppio reale (senza ERRORE ROTONDO) è stampare i bit binari (o i hex nybbles). Un modo per farlo è scrivere double
su a union
e quindi stampare il valore intero dei bit.
union {
double d;
uint64_t u64;
} x;
x.d = 1.1;
std::cout << std::hex << x.u64;
Questo ti darà la precisione accurata del 100% del doppio ... e sarà assolutamente illeggibile perché gli umani non possono leggere il doppio formato IEEE! Wikipedia ha una buona stesura su come interpretare i bit binari.
Nel C ++ più recente, puoi farlo
std::cout << std::hexfloat << 1.1;
Ecco come visualizzare un doppio con la massima precisione:
double d = 100.0000000000005;
int precision = std::numeric_limits<double>::max_digits10;
std::cout << std::setprecision(precision) << d << std::endl;
Questo mostra:
100,0000000000005
max_digits10 è il numero di cifre necessarie per rappresentare in modo univoco tutti i doppi valori distinti. max_digits10 rappresenta il numero di cifre prima e dopo il punto decimale.
Non usare set_precision (max_digits10) con std :: fixed.
In notazione fissa, set_precision () imposta il numero di cifre solo dopo il punto decimale. Ciò non è corretto poiché max_digits10 rappresenta il numero di cifre prima e dopo il punto decimale.
double d = 100.0000000000005;
int precision = std::numeric_limits<double>::max_digits10;
std::cout << std::fixed << std::setprecision(precision) << d << std::endl;
Questo visualizza un risultato errato:
100,00000000000049738
Nota: sono richiesti file di intestazione
#include <iomanip>
#include <limits>
100.0000000000005
non viene rappresentato esattamente come double
. (Potrebbe sembrare che dovrebbe, ma non lo è, perché viene normalizzato , cioè la sua rappresentazione binaria). Per vedere questo, provare: 100.0000000000005 - 100
. Abbiamo capito 4.973799150320701e-13
.
Come posso stampare un
double
valore con la massima precisione usando cout?
Usa hexfloat
o
usa scientific
e imposta la precisione
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
Troppe risposte riguardano solo una delle 1) basi 2) layout fisso / scientifico o 3) precisione. Troppe risposte con precisione non forniscono il valore adeguato necessario. Da qui questa risposta a una vecchia domanda.
A double
è sicuramente codificato usando la base 2. Un approccio diretto con C ++ 11 è di stampare usando std::hexfloat
.
Se un output non decimale è accettabile, abbiamo finito.
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
fixed
o scientific
?A double
è un tipo a virgola mobile , non un punto fisso .
Do Non utilizzare std::fixed
come fallisce stampare piccole double
come qualche cosa ma 0.000...000
. In generale double
, stampa molte cifre, forse centinaia di informazioni discutibili.
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
Per stampare con la massima precisione, utilizzare innanzitutto std::scientific
"scrivere i valori in virgola mobile nella notazione scientifica". Si noti che il valore predefinito di 6 cifre dopo il punto decimale, un importo insufficiente, viene gestito nel punto successivo.
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
UN double
codifica che utilizza la base binaria 2 codifica la stessa precisione tra varie potenze di 2. Questo è spesso 53 bit.
[1.0 ... 2.0) ci sono 2 53 diversi double
,
[2.0 ... 4.0) ci sono 2 53 diversi double
,
[4.0 ... 8.0) ci sono 2 53 diversi double
,
[8.0 ... 10.0) ci sono 2 / 8 * 2 53 diversidouble
.
Tuttavia, se stampa di codici a decimale con N
cifre significative, il numero di combinazioni [1,0 ... 10,0) è 9/10 * 10 N .
Qualunque sia la scelta N
(precisione), non ci sarà un mapping uno a uno tra double
e il testo decimale. Se N
viene scelto un valore fisso , a volte sarà leggermente più o meno del necessario per determinati double
valori. Potremmo sbagliare su troppo pochi ( a)
sotto) o troppi ( b)
sotto).
3 candidati N
:
a) Usare un N
modo così quando si converte da testo double
- testo arriviamo allo stesso testo per tutti double
.
std::cout << dbl::digits10 << '\n';
// Typical output
15
b) Usa un N
così quando convertiamo da double
-testo- double
arriviamo allo stesso double
per tutti double
.
// C++11
std::cout << dbl::max_digits10 << '\n';
// Typical output
17
Quando max_digits10
non è disponibile, tieni presente che a causa degli attributi base 2 e base 10 digits10 + 2 <= max_digits10 <= digits10 + 3
, possiamo usaredigits10 + 3
per assicurare che vengano stampate cifre decimali sufficienti.
c) Utilizzare un valore N
che varia con il valore.
Ciò può essere utile quando il codice desidera visualizzare un testo minimo ( N == 1
) o il valore esatto di a double
( N == 1000-ish
nel caso di denorm_min
). Tuttavia, poiché si tratta di "lavoro" e probabilmente non dell'obiettivo dell'OP, verrà accantonato.
Di solito è b) che viene utilizzato per "stampare un double
valore con la massima precisione". Alcune applicazioni potrebbero preferire a) errori nel non fornire troppe informazioni.
Con .scientific
, .precision()
imposta il numero di cifre da stampare dopo il punto decimale, quindi le 1 + .precision()
cifre vengono stampate. Il codice ha bisogno di max_digits10
cifre totali, quindi .precision()
viene chiamato con a 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
//1234567890123456 17 total digits
precision()
imposta il numero di cifre decimali per la modalità scientifica. Senza specificare scientific
, imposta il numero totale di cifre, escluso l'esponente. Potresti comunque finire con un risultato scientifico, a seconda del valore numerico, ma potresti anche ottenere meno cifre di quanto specificato. Esempio: i cout.precision(3); cout << 1.7976931348623158e+308; // "1.8e+308"
risultati per printf
potrebbero essere diversi. Cose confuse che uno dovrebbe essere consapevole.
char buf[DBL_DECIMAL_DIG + 3 + 5]; sprintf(buf, "%.*g", DBL_DECIMAL_DIG, d);
I caratteri aggiuntivi sono per: segno, punto decimale, zero finale, e [+ | -], 3 cifre per l'esponente ( DBL_MAX_10_EXP = 308). Quindi il numero totale di caratteri richiesti è 25.
printf("%.12f", M_PI);
% .12f significa virgola mobile, con precisione di 12 cifre.
Più facilmente ...
#include <limits>
using std::numeric_limits;
...
cout.precision(numeric_limits<double>::digits10 + 1);
cout << d;
Con ostream :: precision (int)
cout.precision( numeric_limits<double>::digits10 + 1);
cout << M_PI << ", " << M_E << endl;
cederà
3.141592653589793, 2.718281828459045
Perché devi dire "+1" Non ne ho idea, ma la cifra in più che ne ottieni è corretta.
Questo mostrerà il valore fino a due cifre decimali dopo il punto.
#include <iostream>
#include <iomanip>
double d = 2.0;
int n = 2;
cout << fixed << setprecison(n) << d;
Vedi qui: Notazione a virgola fissa
Usa notazione a virgola mobile fissa Imposta il flag del formato floatfield per il flusso str su fisso.
Quando floatfield è impostato su fisso, i valori in virgola mobile vengono scritti usando la notazione in virgola fissa: il valore viene rappresentato con esattamente quante cifre nella parte decimale come specificato dal campo di precisione (precisione) e senza parte esponente.
Imposta precisione decimale Imposta la precisione decimale da utilizzare per formattare i valori in virgola mobile sulle operazioni di output.
Se hai familiarità con lo standard IEEE per rappresentare i virgola mobile, sapresti che è impossibile mostrare i virgola mobile con la massima precisione fuori dallo scopo dello standard , vale a dire, si tradurrà sempre in un arrotondamento del valore reale.
Devi prima verificare se il valore rientra nell'ambito , se sì, quindi utilizzare:
cout << defaultfloat << d ;
Usa notazione a virgola mobile predefinita Imposta il flag del formato floatfield per lo stream str su defaultfloat.
Quando floatfield è impostato su defaultfloat, i valori in virgola mobile vengono scritti utilizzando la notazione predefinita: la rappresentazione utilizza tutte le cifre significative necessarie fino alla precisione decimale del flusso (precisione), contando entrambe le cifre prima e dopo il punto decimale (se presente ).
Questo è anche il comportamento predefinito di cout
, il che significa che non lo usi esplicitamente.
fixed
? Condouble h = 6.62606957e-34;
,fixed
mi dà0.000000000000000
escientific
uscite6.626069570000000e-34
.