2015-02-04 5 views
5

Sono nuovo di C e quando si esegue il codice qui sotto, il valore che viene messo fuori è 12098 anziché 12099.Moving decimale a destra in c

Sono consapevole che lavorare con i decimali comporta sempre un grado di inaccuratezza, ma esiste un modo per spostare con precisione il punto decimale a destra di due posizioni ogni volta?

#include <stdio.h> 

int main(void) 
{ 
    int i; 
    float f = 120.99; 

    i = f * 100; 
    printf("%d", i); 
} 
+0

Prova questa 'float i, f = 120.99f;'. – haccks

+0

nessuno nel C++ standard, hai bisogno di un tipo decimale, come http://sourceforge.net/projects/stddecimal/ – sp2danny

+0

Usa 'ftoa()' e copia ogni numero in un buffer 'char', saltando il carattere del punto decimale tramite' isdigit() '. –

risposta

0

È possibile utilizzare

float f = 120.99f 

o

double f = 120.99 

di default C Conservare valori in virgola mobile come doppia, quindi se di metterle in float fusione implicita variabile è accaduto ed è male ...
penso che funzioni.

+0

nessun lancio avviene quando si memorizza un valore 'double' in una variabile' float'. Quello che succede è una conversione implicita. –

+0

float è 32 valore e double è un valore a 64 bit e il loro algoritmo di memorizzazione è diverso, quindi il casting tra di essi è pericoloso. puoi vedere [Wikipeadia] (http://en.wikipedia.org/wiki/Floating_point) per i dettagli. –

+0

per favore non insegnarmi i numeri in virgola mobile. Sono perfettamente consapevole delle carenze nella conversione tra numeri FP di diversa precisione. Mi riferivo alla formulazione errata nella tua risposta (un "cast" è una conversione esplicita per definizione, quindi una conversione implicita non può essere definita un "cast".) –

5

Utilizzare la funzione

float f = 120.99; 
int i = round(f * 100.0); 

Essere consapevoli però round, che un float ha in genere solo 6 o 7 cifre di precisione, quindi non c'è un valore massimo in cui questo funzionerà. Il valore più piccolo di float che non verrà convertito correttamente è il numero 131072.01. Se moltiplichi per 100 e round, il risultato sarà 13107202.

È possibile estendere l'intervallo dei numeri utilizzando i valori double, ma anche un intervallo double ha un intervallo limitato. (A double ha 16 o 17 cifre di precisione.) Ad esempio, il codice seguente stamperà 10000000000000098

double d = 100000000000000.99; 
uint64_t j = round(d * 100.0); 
printf("%llu\n", j); 

Questo è solo un esempio, trovando il numero più piccolo è che supera la precisione di un double è lasciato come esercizio per il lettore.

4

Usare l'aritmetica in virgola fissa su interi:

#include <stdio.h> 

#define abs(x) ((x)<0 ? -(x) : (x)) 

int main(void) 
{ 
    int d = 12099; 
    int i = d * 100; 
    printf("%d.%02d\n", d/100, abs(d)%100); 
    printf("%d.%02d\n", i/100, abs(i)%100); 
} 
1

Se vuoi di continuare ad operare sul numero come un numero in virgola mobile, allora la risposta è più o meno non. Ci sono varie cose che puoi fare per i numeri piccoli, ma man mano che i tuoi numeri aumentano, avrai dei problemi.

Se si desidera stampare solo il numero, la mia raccomandazione sarebbe quella di convertire il numero in una stringa, quindi spostare il punto decimale lì. Questo può essere leggermente complicato a seconda di come rappresenti il ​​numero nella stringa (esponenziale e cosa no).

Se desideri che funzioni e non ti preoccupi di non utilizzare virgola mobile, ti consigliamo di cercare un numero qualsiasi di librerie decimali fisse.

2

Il problema è che il float viene rappresentato internamente utilizzando IEEE-754. Questo è nella base 2 e non nella base 10. non ha, né ha 120.99.

cosa succede realmente è che a causa di virgola mobile inacuracy, IEEE-754 galleggiare vicino al valore decimale 120.99 moltiplicato per 100 è leggermente inferiore 12099, quindi è troncato a 12098. Il compilatore dovrebbe averti avvertito di avere un troncamento da float su (il mio).

L'unico modo infallibile per ottenere quello che ci si aspetta è quello di aggiungere 0.5 al galleggiante prima che il troncamento a int:

i = (f * 100) + 0.5 

Ma fate attenzione virgola mobile sono intrinsecamente imprecise durante l'elaborazione di valori decimali.

Edit:

Naturalmente per i numeri negativi, dovrebbe essere i = (f * 100) - 0.5 ...

+0

@chux: Post modificato. Grazie per la precisione –

+0

Punto minore: "IEEE-754" specifica sia i formati decimali in virgola mobile che in virgola mobile di cui la tua risposta si basa su quelli binari molto più popolari. I formati decimali erano piuttosto popolari in passato e ho il sospetto che avranno un risorgere minore proprio per questo tipo di problemi. – chux

+0

@chux: Ho citato la pagina di Wikipedia che fornisce maggiori dettagli per questo motivo tra gli altri. Ma se il sistema OP utilizzava decimale IEEE 754, non avrebbe riscontrato alcun problema :-) –