conversione char a double con atof, perchè arrotonda male?

Buongiorno, vorrei convertire un char array in double usando atof, ma in alcuni "casi" la conversione arrotonda male (sbaglia l'ultimo decimale). Poco male, nell'uso come coordinata GPS questo equivale a pochi cm, ma vorrei capire "perché"!

Esempio:
double LAT1;
char LAT1CHAR[10]; //il dato ha due cifre e sei decimali
String subSD;

String SDstring = "LAT1:43.945035;LNG1:43.945035;"; //parto da una stringa che contiene le coordinate
subSD= SDstring.substring(5,14); //estraggo la latitudine
subSD.toCharArray(LAT1CHAR, 10); //metto nel char array
LAT1=atof(LAT1CHAR); //converto

Il monitor seriale mi stampa:
subSD= 43.945035 //quindi estraggo bene dalla stringa
LAT1CHAR= 43.945035 // quindi converto bene in char array
LAT1= 43.945034 // e mi sbaglia il decimale!!

NOTA: ho provato altri numeri a caso e a volte lo fa e a volt no, converte bene... ma non sono riuscito a capire quando.

come sempre grazie a tutti per l'aiuto!

Te l'ho gà chiesto QUI e NON hai risposto, te lo richiedo ... di che Arduino stai parlando ? ? ?

Guglielmo

Ho provato su un Arduino Nano e stamattina anche su un Arduino UNO.
Scusa ma non pensavo fosse riferito al discorso dell'atof

... mah ... quello che forse non ti è chiaro è che sulle MCU AVR che montano i vari Arduino, i double NON esistono e tutto è trattato come normali float (32 bit) per cui, come chiaramente riportato nel reference:

Floats have only 6-7 decimal digits of precision. That means the total number of digits, not the number to the right of the decimal point. Unlike other platforms, where you can get more precision by using a double (e.g. up to 15 digits), on the Arduino, double is the same size as float.

Quindi ... non ti aspettare chissà quale precisione e dimentica di fare calcoli "seri" con le coordinate GPS per i quali ... occorrono dei veri duouble (64 bit).

Guglielmo

P.S.: ... e se cerchi, l'utente astrobeed, ne ha più volte ampiamente parlato qui sul forum ::slight_smile:

E' vero ma qui non ci sono calcoli in mezzo.
Si parte dalla stringa subSD= 43.945035
Che poi viene convertita in un char array LAT1CHAR= 43.945035
Al momento di convertirlo in float scatta, forse, un arrotondamento?
Perchè ottiene LAT1= 43.945034?

lcursi
ti capita sempre oppure a seconda del valore dell'ultimo decimale?

zoomx:
Perchè ottiene LAT1= 43.945034?

Perché, come riportato, le cifre significative sono SOLO 6, massimo, in alcuni casi 7... e quel numero ne ha già 8 !!! In quelle condizioni NON è determinato cosa contengono le cifre successive ... ::slight_smile:

Guglielmo

zoomx:
E' vero ma qui non ci sono calcoli in mezzo.
Si parte dalla stringa subSD= 43.945035
Che poi viene convertita in un char array LAT1CHAR= 43.945035
Al momento di convertirlo in float scatta, forse, un arrotondamento?
Perchè ottiene LAT1= 43.945034?

lcursi
ti capita sempre oppure a seconda del valore dell'ultimo decimale?

varia a seconda del numero, ma non dell'ultimo decimale e basta. Nel senso che a volte funziona correttamente, a volte no, e facendo vari test non sono riuscito a trovare una regola :frowning:

Se, come ha scritto Guglielmo, le cifre significative possono essere solo 6 mi sa che dovrai adattarti, la regola è che dopo le prime 6 cifre le altre possono essere diverse.
Dovresti cambiare MCU, specialmente se ci vuoi fare calcoli sopra.

zoomx:
Se, come ha scritto Guglielmo, le cifre significative possono essere solo 6 mi sa che dovrai adattarti, la regola è che dopo le prime 6 cifre le altre possono essere diverse.
Dovresti cambiare MCU, specialmente se ci vuoi fare calcoli sopra.

all'atto pratico, nell'uso come coordinata GPS, si passa da "sapere in che punto sei in una stanza" a "sapere in che stanza sei", quindi alla fine compatibile con la precisione che una antenna GPS di basso costo può dare.

Grazie a tutti

lcursi:
all'atto pratico, nell'uso come coordinata GPS, si passa da "sapere in che punto sei in una stanza" a "sapere in che stanza sei" ...

... magari diciamo in "che appartamento" sei :smiley: :smiley: :smiley: ... e se poi provi a fare in questo modo calcoli sulla distanza tra due punti ... l'errore è piuttosto notevole !

Guglielmo

P.S.: ricordatevi che i float sono rappresentanti secondo lo standard IEEE single precision con un bit per il segno, 8 bit per l'esponente e 23 bit per la parte decimale.

naaaaa che pessimismo!
Ad esempio fra 43.681781° - 10.710182°
e
43.681785° - 10.710187°
dove quindi le cifre sono cambiate entrambe e più di qualche punto, la distanza è 70 cm circa

se cambio un po' anche la penultima cifra, tipo:
43.681795° - 10.710197°
la distanza è 2 m circa.

Considerando che la precisione di un segnale è di qualche metro.. ci si può stare, no?

lcursi:
naaaaa che pessimismo!
Ad esempio fra 43.681781° - 10.710182°
e
43.681785° - 10.710187°
dove quindi le cifre sono cambiate entrambe e più di qualche punto, la distanza è 70 cm circa

Sicuro ? :smiling_imp:

Prova a fare il calcolo con ARDUINO della vera distanza tra due punti (Long1,Lat1, Long2, Lat2) e non tu con la calcolatrice ... con tutti gli arrotondamenti del caso che usa per ogni operazione con i float e fammi sapere :wink:

Esempio ... usa una formula che da una buona approssimazione:

p1 = (minlon, minlat) //longitudine e latitudine in radianti
p2 = (maxlon, maxlat) //longitudine e latitudine in radianti

dist = arccos( sin(minlat) * sin(maxlat) + cos(minlat) * cos(maxlat) * cos(maxlon – minlon) ) * 6371
(6371 è il raggio della Terra in Km; dist è espressa in Km).

Guglielmo

P.S.: Per una completa trattazione si può andare QUI

beh si! ho fatto una misura con il righello di Google Earth, poi anche su un sito che fa il calcolo on line
boulter.com/gps/distance

nel primo caso 0m, nel secondo approssima a 1m

facciamo anche un esempio sui 100m di distanza (rispetto al punto di prima), scelgo: 43.682355° 10.711171°
questo punto è per google earth a 101m circa
per il sito di cui sopra : 0,1km (direi che ci siamo)

se cambio la PENULTIMA cifra decimale 43.682395° - 10.711121°
per Googole si fa a 101,87
per il sito resta 0,1km (precisione scarsina però)

allora provo Excel e la formula 6372,795477598* ARCCOS((SEN(B5) * SEN(C5) + COS(B5) * COS(C5) * COS(B6-C6)))
B5 e C5 partenza e B6 C6 arrivo
in questo caso le distanze sono
101,97 m nel primo caso
101,80 nel secondo

dire che si parla di posizine dei mobili dentro una stanza :slight_smile:

Non hai capito: devi fare il calcolo su Arduino, non su Excel, che ha una precisione molto maggiore nei calcoli in virgola mobile.

Giusto per saperlo, cosa non ti era chiaro in questo?
http://forum.arduino.cc/index.php?topic=589255.msg4008149#msg4008149
che mi sembrava che qui ci eravamo già arrivati....

SukkoPera:
Non hai capito: devi fare il calcolo su Arduino, non su Excel, che ha una precisione molto maggiore nei calcoli in virgola mobile.

obiettivo era valutare l'impatto teorico dell'errore dovuto alla conversione "atof" errata, ovvero: quanto conta in teoria l'ultima cifra? direi poco, visto che la penultima fa variare di 1-2 m circa

Standardoil:
Giusto per saperlo, cosa non ti era chiaro in questo?
Aiuto per calcolo (distanza punti GPS) - uso delle variabili sbagliato? - #4 by Standardoil - Software - Arduino Forum
che mi sembrava che qui ci eravamo già arrivati....

non mi pare che nell'altro post si parli della conversione atof (che è prima ed indipendente dal calcolo della distanza)
semmai se ne parla qui: string -> double con sei cifre decimali - #12 by lcursi - Software - Arduino Forum
nella quale mi si diceva "Quindi usa la atof() e quindi nessun arrotondamento" e siccome invece arrotonda, ho chiesto, anche per capire se sbagliavo io...

lcursi:
obiettivo era valutare l'impatto teorico dell'errore dovuto alla conversione "atof" errata, ovvero: quanto conta in teoria l'ultima cifra? direi poco, visto che la penultima fa variare di 1-2 m circa

... se non devi fare alcun calcolo, la cosa era già chiarita, il problema è se uno deve/vuole fare i calcoli su Arduino ... è li che casca l'asino !!!

Guglielmo

gpb01:
... se non devi fare alcun calcolo, la cosa era già chiarita, il problema è se uno deve/vuole fare i calcoli su Arduino ... è li che casca l'asino !!!

Guglielmo

il calcolo lo farò con la funzione presente nella libreria TinyGPS, come abbiamo scritto. E poi validerò il tutto sul campo:)

Come diceva il buon dottore: neanche gli dei!