Go Down

Topic: "trovare" numero di cifre dopo il punto decimale (Read 5250 times) previous topic - next topic

GINGARDU

volevo un aiuto (da qualche anima pia) per come fare a trovare quante cifre ci sono dopo il punto decimale,
esempio;  float  21,34        k assume il valore 2                   due cifre dopo il decimale
esempio;  float  21,5          k assume il valore 1                      una cifra dopo il decimale
esempio;  float  123,345   k assume il valore 3                     tre cifre dopo il decimale


nid69ita

#1
Nov 24, 2013, 11:35 pm Last Edit: Nov 24, 2013, 11:41 pm by nid69ita Reason: 1
Converti in stringa e calcoli dove è la virgola può essere un metodo.

Altra idea, prendi solo la parte decimale (togli la parte intera usando un long)
Poi moltiplichi per 10 con un ciclo finchè la cifra non diventa ==0
Quante volte hai loopato dovrebbe essere quanti decimali hai.
my name is IGOR, not AIGOR

GINGARDU

per la parte stringa ancora non so da che parte si comincia   =(

invece per moltiplicare per 10 ci stavo arrivando ma non ci sono riuscito

e te mi confondi   $)  come faccio a prendere la parte decimale con un long?  se mai prendo quella intera  :~

astrobeed


volevo un aiuto (da qualche anima pia) per come fare a trovare quante cifre ci sono dopo il punto decimale,
esempio;  float  21,34        k assume il valore 2                   due cifre dopo il decimale
esempio;  float  21,5          k assume il valore 1                      una cifra dopo il decimale
esempio;  float  123,345   k assume il valore 3                     tre cifre dopo il decimale


C'è un problema di fondo legato a come sono gestiti i float.
Dato che i float sono una rappresentazione di natura esponenziale non avrai quasi mai un valore netto nel numero di decimali, ovvero invece di 1.12 hai una cosa del tipo 1.119256 con tante cifre decimali quante ne consente la rappresentazione float, tipicamente fino ad un massimo di 6-7 a seconda del valore se la parte intera è 0, altrimenti il numero di cifre viene ripartito tra parte intera e decimale.

Scientia potentia est

nid69ita

#4
Nov 25, 2013, 03:10 pm Last Edit: Nov 25, 2013, 03:13 pm by nid69ita Reason: 1

per la parte stringa ancora non so da che parte si comincia   =(

invece per moltiplicare per 10 ci stavo arrivando ma non ci sono riuscito

e te mi confondi   $)  come faccio a prendere la parte decimale con un long?  se mai prendo quella intera  :~

Ho scritto: "Altra idea, prendi solo la parte decimale (togli la parte intera usando un long)"
Dovrebbe funzionare. Non posso provare, non ho Arduino dietro.
Code: [Select]
float varf=12.45;
float temp= varf-long(varf);


Però occhio a quello che dice @astro. Perciò secondo me è meglio usare la conversione in stringa:
Code: [Select]
float varf=12.45;
char buf[10];
dtostrf(varf,1,8,buf);     // in buf float in formato testo, voglio 1 interi e 8 decimali
// adesso posso cercare la virgola nella stringa

Sarebbe meglio anche provare a stampare su Serial Monitor la stringa buf per verificare come esegue la conversione, tanto per essere sicuri.

La dtostrf() converte da float a stringa: http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html#ga060c998e77fb5fc0d3168b3ce8771d42
my name is IGOR, not AIGOR

GINGARDU



volevo un aiuto (da qualche anima pia) per come fare a trovare quante cifre ci sono dopo il punto decimale,
esempio;  float  21,34        k assume il valore 2                   due cifre dopo il decimale
esempio;  float  21,5          k assume il valore 1                      una cifra dopo il decimale
esempio;  float  123,345   k assume il valore 3                     tre cifre dopo il decimale


C'è un problema di fondo legato a come sono gestiti i float.
Dato che i float sono una rappresentazione di natura esponenziale non avrai quasi mai un valore netto nel numero di decimali, ovvero invece di 1.12 hai una cosa del tipo 1.119256 con tante cifre decimali quante ne consente la rappresentazione float, tipicamente fino ad un massimo di 6-7 a seconda del valore se la parte intera è 0, altrimenti il numero di cifre viene ripartito tra parte intera e decimale.




visto che molti  numeri dopo la virgola   alla fine dei conti sono più un " disturbo che un utilità   già 2 decimali  dovrebbero bastare per la maggior parte delle misure,   
non c'è un sistema per troncare a 2 o al massimo 3 decimali  un numero float ?

leo72

Code: [Select]
non c'è un sistema per troncare a 2 o al massimo 3 decimali  un numero float ?
Una banalissima moltiplicazione per 100 o per 1000, a seconda se vuoi 2 o 3 cifre decimali, depositare il risultato in un intero, e poi ridividere per 100 o per 1000.
Il parcheggio in una variabile intera tronca la parte decimale, salvando le cifre che ti interessano (hai moltiplicato per 100 o 1000, ricordi?) quindi esse sono diventate intere.
Esempio:
Code: [Select]
float a = 12.456789;
int b = a * 100; //adesso b vale esattamente 1245
float c = b / 100; //ora c vale (quasi) esattamente 12.45

astrobeed

#7
Nov 25, 2013, 04:24 pm Last Edit: Nov 25, 2013, 04:57 pm by astrobeed Reason: 1

Code: [Select]
non c'è un sistema per troncare a 2 o al massimo 3 decimali  un numero float ?
Una banalissima moltiplicazione per 100 o per 1000, a seconda se vuoi 2 o 3 cifre decimali, depositare il risultato in un intero, e poi ridividere per 100 o per 1000.
I


Il problema è che nel momento in cui dividi ottieni nuovamente tante cifre decimali quanto possibile, è una caratteristica dei float e non ci si può fare nulla.
Solo in fase di visualizzazione è possibile troncare i decimali in eccesso, previo arrotondamento altrimenti si rischia di vedere 1.19 invece di 1.20.
Scientia potentia est

leo72

Sì, è giusto, però l'approssimazione che torna fuori può, diciamo, essere quasi ignorata.
Ad esempio, è probabile che 1245/100 dia 12.4500001.
Ai fini dei calcoli si può ignorare quello 0,0000001.

Ecco perché ho scritto "quasi" nel commento  :D

GINGARDU

quindi la vera "tragedia" sta nell'atto della divisione,  e le cifre superflue che cacci via dalla porta rientrano dalla finestra   =(   ?

astrobeed


Ai fini dei calcoli si può ignorare quello 0,0000001.


Diciamo di si, però dato che lo scopo era conoscere il numero di decimali alla fine il problema è sempre lo stesso :)
Scientia potentia est

nid69ita

#11
Nov 25, 2013, 06:00 pm Last Edit: Nov 25, 2013, 06:29 pm by nid69ita Reason: 1
funzione NumDecimali, gli passi il float ritorna numero decimali (non ho provato con numeri grandi):
Code: [Select]
int NumDecimali(float f)
{ char buf[10];       // dieci celle di caratteri che saranno puntate da varabile i           
 dtostrf(f,1,5,buf);       // 12.345 => "12.34500"      converte da float a stringa, 1=dimensione minima 5=numero decimali
 int i=0,n=0;       // i  permette di puntare le varie celle, n conta il numero di decimali
 // cerca il punto, ciclo e aumento i finchè la cella puntata da i è diversa da '.' oppure i è arrivato alla ultima cella
 while(buf[i] !='.' && i<9) {i++; }  
 i++;      // aumenti i di 1 per andare alla cella successiva al punto
 // cerca fino alla prima non '0', verifica anche di non aver raggiunto la fine della stringa ('\0'=carattere fine stringa)
 while(buf[i] !='0' && i<9 && buf[i]!='\0') {i++; n++;}
 return n;
}

void setup()
{ delay(1000);
 Serial.begin(9600);
 Serial.println(NumDecimali(12.0));    // 0
 Serial.println(NumDecimali(12.1));    // 1
 Serial.println(NumDecimali(12.12));   // 2
 Serial.println(NumDecimali(12.123));    // 3
 Serial.println(NumDecimali(12.1234));  // 4
 Serial.println(NumDecimali(12.12345));  // 5
 Serial.println(NumDecimali(12.123456));  // 5
}

void loop()
{}


P.S. non ho usato i puntatori ma la sintassi con le quadre per renderlo più digeribile ai neofiti che non conoscono i puntatori.
my name is IGOR, not AIGOR

GINGARDU


funzione NumDecimali, gli passi il float ritorna numero decimali (non ho provato con numeri grandi):
Code: [Select]
int NumDecimali(float f)
{ char buf[10];
 dtostrf(f,1,5,buf);  // 12.345 => "12.34500"
 //Serial.println(buf);
 int i=0,n=0;
 // cerca il punto
 while(buf[i] !='.' && i<9) {i++; }  
 i++;
 // cerca fino alla prima non 0
 while(buf[i] !='0' && i<9 && buf[i]!='\0') {i++; n++;}
 return n;
}

void setup()
{ delay(1000);
 Serial.begin(9600);
 Serial.println(NumDecimali(12.0));    // 0
 Serial.println(NumDecimali(12.1));    // 1
 Serial.println(NumDecimali(12.12));   // 2
 Serial.println(NumDecimali(12.123));    // 3
 Serial.println(NumDecimali(12.1234));  // 4
 Serial.println(NumDecimali(12.12345));  // 5
 Serial.println(NumDecimali(12.123456));  // 5
}

void loop()
{}



tanks,   sei molto bravo ,  da solo non ci sarei mai arrivato in tempi brevi  =(  se commenti riga per riga (nei limiti del possibile )per capire un po' di più cosa fa fai un favore a me e a qualche altro neofita

nid69ita

Ho messo ora dei commenti al codice nel post sopra.
Ripeto, non ho fatto tutti i test possibili, ad esempio con cifre strane come  1234567.8 (tanta parte intera, pochi decimali). Magari l'array buf è da aumentare (da 10 a 12).
my name is IGOR, not AIGOR

GINGARDU

cosi come è funziona fino a 8 cifre più il punto,   ed 8 cifre bastano ed avanzano per visualizzare qualsiasi cosa,  tanks

Go Up