2010-11-18 13 views
23

Ho bisogno di aiuto per mantenere la precisione di un double. Se assegno un letterale a un doppio, il valore effettivo è stato troncato.Come "cout" il numero corretto di posizioni decimali di un doppio valore?

int main() { 
    double x = 7.40200133400; 
    std::cout << x << "\n"; 
} 

Per il frammento di codice di cui sopra, l'uscita era 7.402
C'è un modo per evitare questo tipo di troncamento? O c'è un modo per calcolare esattamente quanti punti mobili per un double? Ad esempio, number_of_decimal(x) restituirebbe 11, poiché l'input è sconosciuto in fase di esecuzione, quindi non è possibile utilizzare setprecision().


penso che dovrei cambiare la mia domanda: Come convertire un doppio a una stringa senza troncare i punti galleggianti. Ad esempio

#include <iostream> 
#include <string> 
#include <sstream> 

template<typename T> 
std::string type_to_string(T data) { 
    std::ostringstream o; 
    o << data; 
    return o.str(); 
} 

int main() { 
    double x = 7.40200; 
    std::cout << type_to_string(x) << "\n"; 
} 

L'uscita prevista dovrebbe essere 7,40200 ma il risultato effettivo era 7,402. Quindi, come posso aggirare questo problema? Qualche idea?

+1

"L'output atteso" - il problema è con le vostre aspettative. "7.40200 ma il risultato effettivo era 7.402" - quelli sono uguali, quindi niente è stato "troncato". cout non può sapere quanti zeri hai digitato nel tuo file sorgente. –

+0

Vedere [questo] (http://www.cplusplus.com/reference/iostream/ios_base/precision/) per la precisione in virgola mobile. – Benoit

risposta

27

A causa del fatto il float e double vengono memorizzati internamente in binario, quello letterale 7.40200133400 sta in realtà per il numero 7,40200133400000037653398976544849574565887451171875

... così quanta precisione si vuole veramente? :-)

#include <iomanip>  
int main() 
{ 
    double x = 7.40200133400; 
    std::cout << std::setprecision(51) << x << "\n"; 
} 

E sì, questo programma davvero stampa 7,40200133400000037653398976544849574565887451171875!

+0

Ciao Fred, Non voglio alcuna precisione specificata. Voglio solo convertirlo in una stringa come il suo formato originale. Correggimi se ho frainteso le tue istruzioni. Grazie, – Chan

+0

@Chan: vuoi '7.402001334' o' 7.40200133400' o '7.402001334000000'? – fredoverflow

+0

Voglio 7.40200133400, né più né meno. – Chan

9
std::cout << std::setprecision(8) << x; 

noti che setprecision è persistente e tutti i carri successivi si stampa verrà stampata con quella precisione, fino a quando si cambia un valore diverso. Se questo è un problema e si desidera lavorare intorno a questo, si può utilizzare un proxy stringstream oggetto:

std::stringstream s; 
s << std::setprecision(8) << x; 
std::cout << s.str(); 

Per ulteriori informazioni sulla formattazione iostream, controllare la sezione Input/output manipulators in cppreference.

+0

Ciao Kos, ho capito cosa hai detto, ma il problema era che la precisione cambia da un valore all'altro. Ad esempio: 1.233 e 3.99945, uno ha 3 e uno ha 5. – Chan

+0

-1, non quello che l'OP sta chiedendo .. :( – Nim

+3

@Chan: tutti i numeri in virgola mobile hanno la stessa precisione – You

5

Soluzione utilizzando Boost.Format:

#include <boost/format.hpp> 
#include <iostream> 

int main() { 
    double x = 7.40200133400; 
    std::cout << boost::format("%1$.16f") % x << "\n"; 
} 

Questo emette 7.4020013340000004.

Spero che questo aiuti!

+0

Innanzitutto, grazie Daniel. Ma penso che il formato boost :: si comporti esattamente come cout.set (0, std :: ios :: floatfield), e il tuo output non è quello originale. converti il ​​doppio valore in una stringa: – Chan

+0

L'originale è solo qualcosa che hai digitato in un file di testo e non rappresenta necessariamente il valore reale –

3

L'unica risposta a questo che ho trovato è che non c'è modo di farlo correttamente (come nel calcolo delle cifre decimali)! La ragione principale per questo è che la rappresentazione di un numero potrebbe non essere quella che ci si aspetta, ad esempio 128.82, sembra abbastanza innocua, tuttavia la sua rappresentazione effettiva è 128.8199999999 ... come si calcola il numero di cifre decimali?

+1

Puoi aggiungere o rimuovere 0,0000000001, quindi stamparlo di nuovo e vedere se il nuovo output utilizza meno caratteri. L'importo da aggiungere o rimuovere dipende dalla precisione di cui sei soddisfatto. –

+1

A meno che tu non sia veramente preoccupato per quel livello di precisione, nel qual caso probabilmente stai facendo le tue cose, hai solo circa 15 posti. Dopo 15 non hai comunque una buona precisione. –

+0

Infatti, voglio convertire questo valore in una stringa e voglio mantenere il suo formato così come è stato letto da un file. – Chan

17

È necessario utilizzare setiosflags(ios::fixed) e setprecision(x).

Per esempio, cout << setiosflags(ios::fixed) << setprecision(4) << myNumber << endl;

Inoltre, non dimenticare di #include <iomanip.h>.

+2

+1 per ios :: fisso come: setiosflags (ios :: fixed) aiuta per il caso in cui num == (int) num, consente di emettere il numero in formato come 2.00, senza uscita sarà 2 –

2

Rispondere alla tua risposta-modifica: non c'è modo di farlo. Non appena si assegna un valore a double, tutti gli zeri finali vengono persi (al compilatore/computer, 0.402, 0.4020 e 0.40200 sono lo STESSO NUMERO). L'unico modo per mantenere gli zeri finali come indicato è quello di memorizzare i valori come stringhe (o fare trucchetti in cui si tiene traccia del numero di cifre che interessa e formattarlo esattamente a quella lunghezza).

1

Facciamo una richiesta analoga: dopo aver inizializzato un numero intero con 001, dovresti stamparlo con gli zeri iniziali. Quelle informazioni di formattazione semplicemente non sono mai state archiviate.

Per ulteriori informazioni sulla memorizzazione in virgola mobile a doppia precisione, consultare lo standard IEEE 754.

2

Doppie non hanno posizioni decimali. Hanno posti binari. E i posti binari e le cifre decimali sono incommensurabili (perché log2(10) non è un numero intero).

Quello che stai chiedendo non esiste.

Problemi correlati