"trovare" numero di cifre dopo il punto decimale

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

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.

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 :~

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.

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 :~

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.

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:

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: avr-libc: <stdlib.h>: General utilities

astrobeed:

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 ?

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:

float a = 12.456789;
int b = a * 100; //adesso b vale esattamente 1245
float c = b / 100; //ora c vale (quasi) esattamente 12.45

leo72:

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.

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 :smiley:

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

leo72:
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 :slight_smile:

funzione NumDecimali, gli passi il float ritorna numero decimali (non ho provato con numeri grandi):

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.

nid69ita:
funzione NumDecimali, gli passi il float ritorna numero decimali (non ho provato con numeri grandi):

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

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).

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