2009-06-18 15 views
6

Sono di fronte a un problema e non riesco a risolverlo. Hai bisogno di aiuto dai guru. Ecco il codice di esempio: -C++: Come convertire da virgola mobile a stringa senza arrotondamento, troncatura o riempimento?

float f=0.01f; 
printf("%f",f); 

se controlliamo valore nella variabile durante il debug f contiene ',0099,999998 millions' il valore e l'uscita di printf è 0,010 mila.

a. Esiste un modo per forzare il compilatore ad assegnare gli stessi valori alla variabile di tipo float?

b. Voglio convertire float in stringa/array di caratteri. Com'è possibile che solo ed esclusivamente lo stesso valore sia convertito in array stringa/carattere. Voglio assicurarmi che nessuno zeri sia riempito, nessun valore indesiderato è riempito, nessun cambiamento nelle cifre come nell'esempio sopra.

risposta

2

Dai un'occhiata a questo C++ reference. In particolare la sezione sulla precisione:

+0

Penso che stia affrontando un problema con i galleggianti non raddoppia – Aamir

+0

hehe ... questo è bello. Immagino che il downvote originale potrebbe essere stato a causa della mia prima, molto concisa risposta (senza codice sorgente), e anche abbastanza chiara;). – RedBlueThing

+0

Potrebbe anche essere perché ho ignorato l'intero problema di rappresentazione del punto di virgola mobile e ho risposto alla domanda a un livello abbastanza superficiale. – RedBlueThing

2

Ci sono molti numeri reali.

Ci sono solo un numero finito di valori che possono assumere i tipi di dati float, double e long double.

Cioè, ci saranno innumerevoli numeri reali che non possono essere rappresentati esattamente usando quei tipi di dati.

6

È impossibile rappresentare con precisione un numero decimale di base 10 utilizzando i valori di base 2, ad eccezione di un numero molto piccolo di valori (ad esempio 0,25). Per ottenere ciò che ti serve, devi passare dal tipo float/double built-in a una sorta di pacchetto decimale.

1

La ragione per cui il debugger ti fornisce un valore diverso è ben spiegata nel post di Mark Ransom.

Per quanto riguarda la stampa di un float senza arrotondamento, il troncamento e con precisione più completa, manca lo specificatore di precisione: la precisione predefinita per printf è in genere di 6 cifre frazionarie.

provare le seguenti per ottenere una precisione di 10 cifre:

float amount = 0.0099999998; 
printf("%.10f", amount); 

Come nota a margine, un modo più C++ (vs C-style) di fare le cose è con cout:

float amount = 0.0099999998; 
cout.precision(10); 
cout << amount << endl; 
0

Dovresti consultare i tuoi standard di piattaforma per determinare come determinare il formato corretto, dovresti visualizzarlo come un * b^C, dove 'a' è il componente integrale che contiene il segno, 'b' è implementazione definita (Probabilmente fissata da uno standard), e 'C' è l'esponente utilizzato per quel numero.

In alternativa, potresti semplicemente visualizzarlo in esadecimale, non significherebbe nulla per un umano, però, e sarebbe comunque binario per tutti gli scopi pratici. (! E proprio come portatile)

0

Per rispondere alla tua seconda domanda:

è possibile esattamente e senza ambiguità rappresentare carri come stringhe. Tuttavia, ciò richiede una rappresentazione esadecimale. Ad esempio, 1/16 = 0.1 e 10/16 è 0.A.

Con i galleggianti esadecimali, è possibile definire una rappresentazione canonica.Personalmente utilizzerei un numero fisso di cifre che rappresentano il numero sottostante di bit, ma potresti anche decidere di rimuovere gli zero finali. Non c'è alcuna confusione possibile su quali cifre finali siano zero.

Poiché la rappresentazione è esatto, le conversioni sono reversibili: f==hexstring2float(float2hexstring(f))

3

si potrebbe usare boost::lexical_cast in questo modo:

float blah = 0.01; 
string w = boost::lexical_cast<string>(blah); 

variabile w conterrà valore di testo ,00999999978. Ma non riesco a vedere quando ne hai davvero bisogno.

È preferibile utilizzare boost::format per la formattazione accurata mobile come stringa. Il codice seguente mostra come farlo:

float blah = 0.01; 
string w = str(boost::format("%d") % blah); // w contains exactly "0.01" now 
0

Per (b), si potrebbe fare

std::ostringstream os; 
os << f; 
std::string s = os.str(); 
1

Allo stesso modo, è possibile utilizzare lo stdlib.h, lì dentro sono il sprintf, ecvt e fcvt funzioni (o almeno, dovrebbe esserci!).

int sprintf(char* dst,const char* fmt,...); 

char *ecvt(double value, int ndig, int *dec, int *sign); 

char *fcvt(double value, int ndig, int *dec, int *sign); 

sprintf restituisce il numero di caratteri è scritto alla stringa, ad esempio

float f=12.00; 
char buffer[32]; 
sprintf(buffer,"%4.2f",f) // will return 5, if it is an error it will return -1 

un'ECVT e fcvt caratteri di ritorno a static char * località contenenti la zero finale rappresentazioni decimali dei numeri, senza punto decimale, numero più significativo prima, l'offset del punto decimale è memorizzato in dec, il segno in "segno" (1 = -, 0 = +) ndig è il numero di cifre significative da memorizzare e. Se dec < 0, allora è necessario eseguire il pad con -dec zeros pror al punto decimale. Non sei sicuro e non stai lavorando su un sistema Windows7 (che a volte non eseguirà vecchi programmi DOS3). Cerca TurboC versione 2 per Dos 3, ci sono ancora uno o due download disponibili, è un programma relativamente piccolo di Borland che è un piccolo edito/compilatore Dos C/C++ e arriva anche con TASM, il codice macchina a 16 bit 386/486 compilato, è coperto dai file di aiuto come molti altri utili informazioni.

Tutte e tre le routine sono in "stdlib.h", o dovrebbero essere, anche se ho trovato che su VisualStudio2010 sono tutt'altro che standard, spesso sovraccarico di funzioni che trattano caratteri di dimensione WORD e che richiedono di utilizzare le proprie funzioni specifiche invece ... "così tanto per la libreria standard ", mormoro a me stesso quasi ogni volta, "Forse escono per ottenere un dizionario migliore!"

1

In verità l'utilizzo del processore in virgola mobile o del coprocessore o della sezione del chip stesso (la maggior parte sono ora integrati nella CPU), non darà mai risultati matematici accurati, ma forniscono un'accuratezza piuttosto approssimativa, per più risultati accurati, potresti prendere in considerazione la definizione di una classe "DecimalString", che usa nybbles come caratteri decimali e simboli ... e tenta di imitare la matematica di base 10 usando stringhe ... in tal caso, a seconda di quanto a lungo vuoi fare le stringhe , si può anche eliminare la parte esponente del tutto una stringa 256 può rappresentare 1x10^-254 fino a 1^+ 255 in decimali retti usando ASCII reale, più breve se si desidera un segno, ma questo potrebbe rivelarsi molto più lento. Si potrebbe accelerare invertendo l'ordine delle cifre, quindi da sinistra a destra leggono le unità , decine, centinaia, migliaia ....

esempio semplice ad es. "0021" diventa 1200 Questo avrebbe bisogno di "spostamento" verso sinistra e verso destra per allineare i punti decimali prima delle routine, la soluzione migliore è iniziare con le funzioni ADD e SUB, poiché poi si costruirà su di loro nel MUL e funzioni DIV. Se sei su una grande macchina, potresti renderli teoricamente il tempo che desidera il tuo cuore!

Problemi correlati