2009-07-05 30 views
13

Diciamo che l'input da parte dell'utente è un numero decimale, es. 5. (con 4 cifre decimali). Può essere memorizzato liberamente (int, doppio) ecc.C/C++ contando il numero di decimali?

C'è qualche intelligente (o molto semplice) modo di scoprire quanti decimali il numero ha? (Un po 'come la domanda come si trova che un numero è pari o dispari mascherando l'ultimo bit).

+0

Puoi chiarire "quanti decimali ha il numero"? Vuoi dire, quante cifre decimali sono nella parte frazionaria del numero? – Doug

+0

Sì, la tua ipotesi è corretta. – Milan

risposta

15

Due modi che conosco, né molto intelligente, purtroppo, ma questo è più una limitazione dell'ambiente, piuttosto che me :-)

La prima è a sprintf il numero su un grande buffer con una stringa di formato "%.50f", rimuovere gli zero finali e contare i caratteri dopo il punto decimale. Questo sarà limitato dalla famiglia printf stessa. Oppure è possibile utilizzare la stringa come input dall'utente (anziché sprintf in un valore in virgola mobile), in modo da evitare del tutto problemi di virgola mobile.

Il secondo è quello di sottrarre la parte intera quindi moltiplicare iterativamente per 10 e di nuovo sottrarre la parte intera fino a ottenere zero. Questo è limitato dai limiti della rappresentazione computerizzata dei numeri in virgola mobile - in ogni fase è possibile che si verifichi il problema di un numero che non può essere rappresentato esattamente (quindi .2155 potrebbe essere in realtà .215499999998). Qualcosa di simile a quanto segue (non testato, tranne che nella mia testa, che è circa alla pari con un COMX-35):

count = 0 
num = abs(num) 
num = num - int(num) 
while num != 0: 
    num = num * 10 
    count = count + 1 
    num = num - int(num) 

Se si conosce il tipo di numeri si otterrà (ad esempio, saranno tutti Da 0 a 4 cifre dopo il punto decimale), è possibile utilizzare "trucchi" in virgola mobile standard per farlo correttamente. Per esempio, invece di:?

while num != 0: 

uso

while abs(num) >= 0.0000001: 
+1

.2155 non diventerà .21559999999999, ma .2156 potrebbe –

+1

A nessuno piace uno smart-alec :-) Grazie, @quant_dev, l'ho risolto. – paxdiablo

+2

Mi classificherei intelligente solo per il modo in cui hai risposto alla domanda. – ojblass

4

Fuori della parte superiore della mia testa:

inizio con la parte frazionaria: .2155

ripetutamente moltiplicare per 10 e buttare via la parte intera del numero fino ad arrivare a zero. Il numero di passaggi sarà il numero di decimali. ad esempio:

.2155 * 10 = 2.155 
.155 * 10 = 1.55 
.55 * 10 = 5.5 
.5 * 10 = 5.0 

4 passi = 4 cifre decimali

+0

Questo ti dà errori di arrotondamento davvero facilmente. Provalo. – Bim

2

Cosa vuoi dire "memorizzato liberamente (int" Una volta memorizzato in un int, che ha zero decimali a sinistra, chiaramente una doppia viene memorizzato. in una forma binaria, quindi nessuna relazione ovvia o semplice con i "decimali": perché non mantenere l'input come una stringa, giusto il tempo necessario per contare quei decimali, prima di inviarlo alla sua destinazione finale variabile numerica?

2

Qualcosa del genere potrebbe funzionare allo stesso modo:

float i = 5.2154; 
std::string s; 
std::string t; 
std::stringstream out; 
out << i; 
s = out.str(); 

t = s.substr(s.find(".")+1); 
cout<<"number of decimal places: " << t.length(); 
+0

In qualche modo dovresti tenere conto dei numeri che non si adattano perfettamente al float, ovvero se si finisce con 5.215399999999999, probabilmente si vogliono riportare 4 cifre decimali. –

6

Una volta che il numero viene convertito dalla rappresentazione utente (stringa, file gif OCR-edito, qualunque) in un numero a virgola mobile, non si ha necessariamente a che fare con lo stesso numero. Quindi la risposta severa, non molto utile è "No".

Se (caso A) si può evitare la conversione del numero dalla rappresentazione di stringa, il problema diventa molto più facile, è solo bisogno di contare le cifre dopo la virgola e sottrarre il numero di zeri finali.

Se non è possibile farlo (caso B), allora avete bisogno di fare una supposizione circa il numero massimo di decimali, convertire il numero di nuovo in rappresentazione di stringa e intorno ad esso a questo numero massimo utilizzando il round-to-even method. Ad esempio, se l'utente fornisce 1.1 che viene rappresentato come 1.09999999999999 (in modo ipotetico), convertendolo di nuovo in stringa, indovina cosa, "1.09999999999999". Arrotondando questo numero a, diciamo, quattro punti decimali si ottiene "1,1000". Ora si torna al caso A.

0

Suggerirei di leggere il valore come stringa, cercando il punto decimale e analizzando il testo prima e dopo come numeri interi. Nessun errore di virgola mobile o di arrotondamento.

-1

Un modo sarebbe quello di leggere il numero come stringa. Trova la lunghezza della sottostringa dopo il punto decimale ed è il numero di decimali che la persona ha inserito. Per convertire questo in virgola mobile utilizzando

Su una nota diversa; è sempre una buona idea quando si gestiscono operazioni in virgola mobile per memorizzarle in un oggetto speciale che ha una precisione finita. Ad esempio, è possibile memorizzare i punti mobili in un tipo speciale di oggetto denominato "Decimale" in cui l'intera parte numerica e la parte decimale del numero sono entrambi valori. In questo modo hai una precisione finita. Lo svantaggio di questo è che devi scrivere metodi per operazioni aritmetiche (+, -, *, /, ecc.), Ma puoi facilmente sovrascrivere gli operatori in C++. So che questo devia dalla tua domanda iniziale, ma è sempre meglio memorizzare i tuoi decimali in una forma finita. In questo modo puoi anche rispondere alla tua domanda su quanti decimali ha il numero.

+0

È (quasi) mai un buon se devi calcolare qualcosa velocemente. –

1

utilizzando il formato notazione scientifica (per evitare errori di arrotondamento):

#include <stdio.h> 
#include <string.h> 

/* Counting the number of decimals 
* 
* 1. Use Scientific Notation format 
* 2. Convert it to a string 
* 3. Tokenize it on the exp sign, discard the base part 
* 4. convert the second token back to number 
*/ 

int main(){ 

    int counts; 
    char *sign; 
    char str[15]; 
    char *base; 
    char *exp10; 
    float real = 0.00001; 

    sprintf (str, "%E", real); 
    sign= (strpbrk (str, "+"))? "+" : "-"; 

    base = strtok (str, sign); 
    exp10 = strtok (NULL, sign); 

    counts=atoi(exp10); 

    printf("[%d]\n", counts); 

    return 0; 
} 

[5]

1

anni dopo la lotta, ma come ho fatto la mia soluzione in tre linee:

string number = "543.014";  
size_t dotFound; 
stoi(number, &dotFound)); 
string(number).substr(dotFound).size() 

Naturalmente bisogna verificare prima se è veramente un galleggiante (Con stof(number) == stoi(number) per esempio)

Problemi correlati